package com.glsc.ngateway.flowable.controller;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import com.glsc.ngateway.common.api.common.dto.PageDataResult;
import com.glsc.ngateway.common.api.common.utils.PageUtil;
import com.glsc.ngateway.common.api.flowable.dto.*;
import com.glsc.ngateway.common.api.flowable.dto.param.*;
import com.glsc.ngateway.common.api.flowable.resp.*;
import com.glsc.ngateway.common.api.oaflow.dto.FlowDetailFrontDto;
import com.glsc.ngateway.common.api.oaflow.dto.oaflow.FrontFlowEdge;
import com.glsc.ngateway.common.api.oaflow.dto.oaflow.FrontFlowEdgeFoldPoint;
import com.glsc.ngateway.common.api.oaflow.dto.oaflow.FrontFlowNode;
import com.glsc.ngateway.common.api.oaflow.dto.oaflow.NodeTaskAssignees;
import com.glsc.ngateway.common.base.domain.mysql.flowable.FlowableCommentSupplement;
import com.glsc.ngateway.common.base.domain.mysql.flowable.FlowableDetail;
import com.glsc.ngateway.common.base.domain.mysql.flowable.FlowableEhrEmp;
import com.glsc.ngateway.common.base.domain.mysql.flowable.FlowableTenant;
import com.glsc.ngateway.flowable.amqp.MessageSender;
import com.glsc.ngateway.flowable.constant.FlowableConstant;
import com.glsc.ngateway.flowable.service.*;
import com.glsc.ngateway.flowable.service.feignservice.AmproductFeignService;
import com.glsc.ngateway.flowable.service.process.FlowableCommentSupplementService;
import com.glsc.ngateway.flowable.service.process.ProcessService;
import com.glsc.ngateway.flowable.util.CustomInjectUserTaskInProcessInstanceCmd;
import com.glsc.ngateway.flowable.util.GatewayExecutionCompensationUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.logging.log4j.util.Strings;
import org.flowable.bpmn.model.Process;
import org.flowable.bpmn.model.*;
import org.flowable.common.engine.impl.identity.Authentication;
import org.flowable.common.engine.impl.interceptor.Command;
import org.flowable.common.engine.impl.interceptor.CommandContext;
import org.flowable.engine.*;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.history.HistoricProcessInstanceQuery;
import org.flowable.engine.impl.dynamic.DynamicUserTaskBuilder;
import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
import org.flowable.engine.impl.persistence.entity.HistoricProcessInstanceEntityImpl;
import org.flowable.engine.impl.util.condition.ConditionUtil;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.engine.task.Attachment;
import org.flowable.engine.task.Comment;
import org.flowable.image.ProcessDiagramGenerator;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskQuery;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.flowable.task.service.impl.persistence.entity.TaskEntityImpl;
import org.flowable.variable.api.history.HistoricVariableInstance;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

@RestController
@RequestMapping(value = "/process")
@Api(value = "flowable流程引擎主类", tags = {"flowable流程引擎主类"})
public class ProcessController {

    @Resource(name = "transactionManagerMysql")
    private PlatformTransactionManager transactionManager;

    private static Logger logger = LoggerFactory.getLogger(ProcessController.class);
    @Autowired
    FlowableCommonService flowableCommonService;
    @Autowired
    FlowableDetailService flowableDetailService;
    @Autowired
    FlowableCopyService flowableCopyService;
    @Autowired
    FlowableEhrEmpService flowableEhrEmpService;
    @Resource
    GatewayExecutionCompensationUtil util;
    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private ProcessEngine processEngine;
    @Autowired
    private HistoryService historyService;
    @Resource
    FlowableTenantService flowableTenantService;
    @Autowired
    private AmproductFeignService amproductFeignService;
    @Resource
    private MessageSender sender;
    @Autowired
    ProcessService processService;
    @Resource
    private FlowableCommentSupplementService flowableCommentSupplementService;

    @RequestMapping(method = RequestMethod.GET, value = "/testAmInterface")
    public String testAmInterface() {
        return amproductFeignService.findAmProductUserIdList("amprod.role.运管TA组").getData().toString();
    }
//
//    @RequestMapping("/user1")
//    public void getemp(@RequestParam("userId") String userId) {
//
//        service.getemp(userId);
//        return;
//    }

//    @RequestMapping("/findAmGroup")
//    public void findAmGroup(@RequestParam("requestParam") String requestParam) {
//        //Result{code=10000, message='OK', data='[wangjx, yangyl]}
//        logger.info(eurekaAmproductFeignService.findAmProductUserIdList(requestParam).toString());
//        return;
//    }


    @RequestMapping("/alert")
    public void getemp(@RequestParam("id") String id) {

        runtimeService.signalEventReceived("theSignal");
        List<Execution> executions = runtimeService.createExecutionQuery()
                .signalEventSubscriptionName("theSignal")
                .list();
        return;
    }

    /**
     * 更新流程标题
     */
    @RequestMapping(method = RequestMethod.POST, value = "/updateProcessTitle")
    @ApiOperation(value = "更新流程标题", notes = "更新流程标题")
    public FlowableResponse<ResponseMsgDto> updateProcessTitle(@RequestBody ParamUpdateTitleDto paramUpdateTitleDto) {
        try {
            String newtitle = paramUpdateTitleDto.getTitle();
            String processId = paramUpdateTitleDto.getProcessId();
            if (StringUtils.isEmpty(newtitle) || StringUtils.isEmpty(processId)) {
                return FlowableResponse.error("更新流程标题接口参数为空！");
            }

            long count = runtimeService.createProcessInstanceQuery().processInstanceId(processId).count();
            if (count == 0) {
                //已经结束流程
                count = flowableCommonService.updateProcessTitle(processId, newtitle);
                if (count > 0) {
                    logger.info("已经结束流程标题更新完成：{}", paramUpdateTitleDto);
                } else {
                    return FlowableResponse.error("更新流程标题接口未找到该流程！processId=" + processId);
                }
            }
            runtimeService.setProcessInstanceName(processId, newtitle);
            //businesskey 是与表单有关暂时不用 理论上是（key.表单id） 目前先不用
            ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
            String businesskey = pi.getProcessDefinitionKey() + "." + newtitle;
            runtimeService.updateBusinessKey(processId, businesskey);

            flowableDetailService.batchUpdateTitle(processId, newtitle);
            logger.info("更新流程标题成功");
            return FlowableResponse.success("更新流程标题成功");
        } catch (Exception e) {
            logger.info("更新流程标题异常！", e);
            return FlowableResponse.error(e.getMessage());
        }
    }

    /**
     * 删除流程
     */
    @RequestMapping(method = RequestMethod.POST, value = "/deleteProcess")
    @ApiOperation(value = "删除流程", notes = "删除流程")
    public FlowableResponse<ResponseMsgDto> deleteProcess(@RequestBody ParamDeleteDto processIdList) {
        try {
            List<String> list = processIdList.getProcessIdList();
            if (CollectionUtils.isEmpty(list)) {
                return FlowableResponse.error("删除流程接口参数为空！");
            }
            for (String processId : list) {
                long count = runtimeService.createProcessInstanceQuery().processInstanceId(processId).count();
                if (count > 0) {
                    stopProcessInstanceById(processId, null);
                }
                historyService.deleteHistoricProcessInstance(processId);
                logger.info("流程删除成功");
                List<FlowableDetail> details = flowableDetailService.findDetailByProcessId(processId);
                if (details != null && details.size() > 0) {
                    flowableDetailService.batchUpdateStatus(details, "3");
                }
                logger.info("更新detail表成功");
            }
            return FlowableResponse.success("删除成功");
        } catch (Exception e) {
            return FlowableResponse.error(e.getMessage());
        }
    }

//    /**
//     * 转发流程
//     */
//    @RequestMapping(method = RequestMethod.POST, value = "/forwardTask")
//    @ApiOperation(value = "转发流程", notes = "转发流程分配给其他人")
//    public FlowableResponse<ResponseTurnDto> forwardTask(@RequestBody ParamTurnDto params) {
//
////        DynamicUserTaskBuilder dynamicUserTaskBuilder = new DynamicUserTaskBuilder();
////        dynamicUserTaskBuilder.setDynamicUserTaskCallback();
////
////
////        processEngine.getDynamicBpmnService().injectUserTaskInProcessInstance();
//        Task newtask = taskService.newTask();
//        newtask.setAssignee(params.getUsernameSource());
//        newtask.setName("转发流程任务");
//        newtask.setTenantId(params.getSysid());
//        taskService.saveTask(newtask);
//        return FlowableResponse.success(new ResponseTurnDto(params.getUsernameDestination()));
//    }

    /**
     * 转办流程
     */
    @RequestMapping(method = RequestMethod.POST, value = "/turnTask")
    @ApiOperation(value = "转办流程", notes = "待办人将流程分配给其他人")
    public FlowableResponse<ResponseTurnDto> turnTask(@RequestBody ParamTurnDto params) {
        TaskEntityImpl currTask = (TaskEntityImpl) taskService.createTaskQuery().taskId(params.getTaskId()).singleResult();
        if (currTask != null) {

            Task newtask = taskService.newTask();
            newtask.setAssignee(params.getUsernameSource());
            newtask.setName("转办任务");
            newtask.setTenantId(params.getSysid());
            newtask.setParentTaskId(params.getTaskId());//父任务id
            taskService.saveTask(newtask);
            Authentication.setAuthenticatedUserId(params.getUsernameSource());
            taskService.addComment(newtask.getId(), currTask.getProcessInstanceId(), params.getComment());
            taskService.complete(newtask.getId());
            taskService.setAssignee(params.getTaskId(), params.getUsernameDestination());
            return FlowableResponse.success(new ResponseTurnDto(params.getUsernameDestination()));
        } else {
            return FlowableResponse.error("转办流程失败，请查看！");
        }
    }

    /**
     * 创建流程
     */
    @RequestMapping(method = RequestMethod.POST, value = "/create")
    @ApiOperation(value = "创建流程", notes = "创建新流程")
    public FlowableResponse create(@RequestBody ParamCreateDto params) {

        try {
            String content = params.getContent();
            if (StringUtils.isEmpty(content)) {
                return FlowableResponse.error("创建流程部分失败，content不能为空");
            }
            JSONObject jsoncontent = new JSONObject(content);
            String title = jsoncontent.getString("title");
            if (StringUtils.isEmpty(title)) {
                return FlowableResponse.error("创建流程部分失败，title不能为空");
            }
            String processDefinitionKey = params.getProcessDefinitionKey();
            if (StringUtils.isEmpty(processDefinitionKey)) {
                return FlowableResponse.error("创建流程部分失败，processDefinitionKey不能为空");
            }

            String userid = params.getUserid();
            String sysid = params.getSysid();
            String createComment = params.getCreateComment();
            //  String data = jsmap.getString("data");


            //启动流程
            HashMap<String, Object> map = new HashMap<>();
            map.put("userid", userid);
            map.put("sysid", sysid);
            map.put("content", content);
            map.put("title", title);
            map.put("taskAssignee", params.getTaskAssignee());
            map.put("conditionalVariable", params.getConditionalVariable());

            //创建流程
            Authentication.setAuthenticatedUserId(userid);
            //businesskey 是与表单有关暂时不用 理论上是（key.表单id） 目前先不用     tenantid是系统名称
            String businesskey = processDefinitionKey + "." + title;
            ProcessInstance processInstance = runtimeService.startProcessInstanceByKeyAndTenantId(processDefinitionKey, businesskey, map, sysid);
            logger.info("create:-----" + processInstance.getProcessDefinitionId());

            //给实例设置名称 标题
            runtimeService.setProcessInstanceName(processInstance.getProcessInstanceId(), title);
            //支持skip节点
            runtimeService.setVariable(processInstance.getProcessInstanceId(), "_FLOWABLE_SKIP_EXPRESSION_ENABLED", true);
            //信息入库
            flowableDetailService.addProcessInstanceByCreate(processInstance, sysid, content, userid, title);

            //提醒类流程特殊处理 .标记不需要进入begintask，不需要自动向前走一步
            if (processDefinitionKey.equals("Remind") || "beginTask".equals(params.getCreateToTaskDefinitionKey())) {
                logger.info("停在benginTask状态，不需要自动向前走一步");
            } else {
                //获取该用户待办事项 往前走一步
                List<Task> tasks = taskService.createTaskQuery().taskAssignee(userid).orderByTaskCreateTime().desc().list();
                String taskId = "";
                Task task = null;
                for (Task t : tasks) {
                    if (t.getProcessInstanceId().equals(processInstance.getProcessInstanceId())) {
                        taskId = t.getId();
                        task = t;
                        break;
                    }
                }
                try {
                    //通过审核
                    if (!StringUtils.isEmpty(createComment)) {
                        taskService.addComment(taskId, task.getProcessInstanceId(), createComment);
                    } else {
                        taskService.addComment(taskId, task.getProcessInstanceId(), "发起");
                    }
                    taskService.complete(taskId);
                    //入库
                    flowableDetailService.addProcessInstanceByTask(task, processInstance, sysid, content, title, "create");
                } catch (Exception e) {
                    logger.error("创建流程部分失败，请检查！taskid=" + taskId + ",processid=" + processInstance.getId(), e);
                    return FlowableResponse.error("创建流程部分失败，请检查！taskid=" + taskId + ",processid=" + processInstance.getId() + ",e.getMessage=" + e.getMessage());
                }
            }
            return FlowableResponse.success(new ResponseCreateDto(processInstance.getProcessInstanceId()));
        } catch (Exception e) {
            logger.error("创建流程失败，请检查！", e);
            return FlowableResponse.error("创建流程失败，请检查！e.getMessage=" + e.getMessage());
        }
    }


    /**
     * 查询流程实例列表
     * 统一入口
     */
    @RequestMapping(method = RequestMethod.POST, value = "/searchProcessList")
    @ApiOperation(value = "查询流程实例列表", notes = "查询流程实例列表统一入口")
    public FlowableResponse<PageDataResult<ResponseSituationDto>> searchProcessList(@RequestParam(value = "pageNum") Integer pageNum,
                                                                                    @RequestParam(value = "pageSize") Integer pageSize,
                                                                                    @RequestBody ParamSearchDto params) {

        try {
            Pageable pageable = PageRequest.of(PageUtil.initPageNo(pageNum) - 1, PageUtil.initPageSize(pageSize));

            boolean hasAll = true;
            boolean hasEnd = true;

            if (params.getHasProcessEnd() != null && !"".equals(params.getHasProcessEnd())) {
                if ("1".equals(params.getHasProcessEnd())) {
                    hasAll = false;
                    hasEnd = true;
                } else {
                    hasAll = false;
                    hasEnd = false;
                }
            }
            logger.info("查询流程实例列表 参数params={},{}-{}", params, pageNum, pageSize);

            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
            Date begin = null;
            Date end = null;
            if (!"".equals(params.getBeginDate()) && params.getBeginDate() != null) {
                begin = sdf.parse(params.getBeginDate());
            }
            if (!"".equals(params.getEndDate()) && params.getEndDate() != null) {
                end = sdf.parse(params.getEndDate());
                //解决流程结束时间查询不正确的问题
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(end);
                calendar.add(Calendar.DATE, 1);
                end = calendar.getTime();
            }

            //人员传参要么不传 要么只能传一个
            String title = params.getTitle();
            String startUser = params.getStartUser();
            String dealUser = params.getDealUser();
            String processDefineKeyOrig = params.getProcessDefineKey();
            String sysid = params.getSysid();
            String involveUser = params.getInvolveUser();

            int num = 0;
            if (!StringUtils.isEmpty(startUser)) {
                num++;
            }
            if (!StringUtils.isEmpty(dealUser)) {
                num++;
            }
            if (!StringUtils.isEmpty(involveUser)) {
                num++;
            }
            if (num > 1) {
                logger.error("flowable流程查询流程实例列表参数错误！");
                return FlowableResponse.error("flowable流程查询流程实例列表参数错误！");
            }
            if (num == 0 && StringUtils.isEmpty(processDefineKeyOrig)) {
                logger.error("flowable流程查询流程实例列表没有人员作为参数的时候，processDefineKey必填！");
                return FlowableResponse.error("flowable流程查询流程实例列表没有人员作为参数的时候，processDefineKey必填！");
            }

            List<String> processDefineKeyList = new ArrayList<>();
            if (!StringUtils.isEmpty(processDefineKeyOrig)) {
                String[] tmp = processDefineKeyOrig.split(",");
                for (String t : tmp) {
                    processDefineKeyList.add(t);
                }
            }

            boolean isSysid = true;
            if (StringUtils.isEmpty(sysid)) {
                isSysid = false;
            }
            //组装dto展示
            List<ResponseSituationDto> list = new ArrayList<>();

            //开始行
            Integer pageRowStartNo = ((Long) pageable.getOffset()).intValue();
            Long totalRowcnt = 0L;

            //查询待办
            if (!StringUtils.isEmpty(dealUser)) {
                List<Task> taskPageList = new ArrayList<>();


//                //流程查询，解决增加一个查询条件就需要增加分支的优化，  TODO
//                TaskQuery rowsDataQuery = taskService.createTaskQuery().taskAssignee(dealUser);
//                TaskQuery rowsCountQuery = taskService.createTaskQuery().taskAssignee(dealUser);
//
//                if (isSysid) {
//                    rowsDataQuery = rowsDataQuery.taskTenantId(sysid);
//                    rowsCountQuery = rowsDataQuery.taskTenantId(sysid);
//                }
//                if (CollectionUtils.isNotEmpty(processDefineKeyList)) {
//                    rowsDataQuery = rowsDataQuery.processDefinitionKeyIn(processDefineKeyList);
//                    rowsCountQuery = rowsDataQuery.processDefinitionKeyIn(processDefineKeyList);
//                }
//
//                if (StringUtils.isEmpty(title)) {
//                    rowsDataQuery = rowsDataQuery.processInstanceBusinessKeyLike("%" + title + "%");
//                    rowsCountQuery = rowsDataQuery.processInstanceBusinessKeyLike("%" + title + "%");
//                }
//                taskPageList = rowsDataQuery.orderByTaskCreateTime().desc().listPage(pageRowStartNo, pageSize);
//                totalRowcnt = rowsCountQuery.count();
//                rowsDataQuery.orderByXXX();//可以根据其它条件进行动态排序，TODO

                if (isSysid) {
                    if (CollectionUtils.isEmpty(processDefineKeyList) && StringUtils.isEmpty(title)) {
                        //获取该用户待办事项
                        taskPageList = taskService.createTaskQuery().taskAssignee(dealUser).taskTenantId(sysid).orderByTaskCreateTime().desc().listPage(pageRowStartNo, pageSize);
                        totalRowcnt = taskService.createTaskQuery().taskAssignee(dealUser).taskTenantId(sysid).count();
                    } else if (!CollectionUtils.isEmpty(processDefineKeyList) && StringUtils.isEmpty(title)) {
                        //获取该用户待办事项
                        taskPageList = taskService.createTaskQuery().processDefinitionKeyIn(processDefineKeyList).taskAssignee(dealUser).taskTenantId(sysid).orderByTaskCreateTime().desc().listPage(pageRowStartNo, pageSize);
                        totalRowcnt = taskService.createTaskQuery().processDefinitionKeyIn(processDefineKeyList).taskAssignee(dealUser).taskTenantId(sysid).count();
                    } else if (CollectionUtils.isEmpty(processDefineKeyList) && !StringUtils.isEmpty(title)) {
                        //获取该用户待办事项
                        taskPageList = taskService.createTaskQuery().processInstanceBusinessKeyLike("%" + title + "%").taskAssignee(dealUser).taskTenantId(sysid).orderByTaskCreateTime().desc().listPage(pageRowStartNo, pageSize);
                        totalRowcnt = taskService.createTaskQuery().processInstanceBusinessKeyLike("%" + title + "%").taskAssignee(dealUser).taskTenantId(sysid).count();
                    } else {
                        //获取该用户待办事项
                        taskPageList = taskService.createTaskQuery().processInstanceBusinessKeyLike("%" + title + "%").processDefinitionKeyIn(processDefineKeyList).taskAssignee(dealUser).taskTenantId(sysid).orderByTaskCreateTime().desc().listPage(pageRowStartNo, pageSize);
                        totalRowcnt = taskService.createTaskQuery().processInstanceBusinessKeyLike("%" + title + "%").processDefinitionKeyIn(processDefineKeyList).taskAssignee(dealUser).taskTenantId(sysid).count();
                    }

                } else {
                    if (CollectionUtils.isEmpty(processDefineKeyList) && StringUtils.isEmpty(title)) {
                        //获取该用户待办事项
                        taskPageList = taskService.createTaskQuery().taskAssignee(dealUser).orderByTaskCreateTime().desc().listPage(pageRowStartNo, pageSize);
                        totalRowcnt = taskService.createTaskQuery().taskAssignee(dealUser).count();
                    } else if (!CollectionUtils.isEmpty(processDefineKeyList) && StringUtils.isEmpty(title)) {
                        //获取该用户待办事项
                        taskPageList = taskService.createTaskQuery().processDefinitionKeyIn(processDefineKeyList).taskAssignee(dealUser).orderByTaskCreateTime().desc().listPage(pageRowStartNo, pageSize);
                        totalRowcnt = taskService.createTaskQuery().processDefinitionKeyIn(processDefineKeyList).taskAssignee(dealUser).count();
                    } else if (CollectionUtils.isEmpty(processDefineKeyList) && !StringUtils.isEmpty(title)) {
                        //获取该用户待办事项
                        taskPageList = taskService.createTaskQuery().processInstanceBusinessKeyLike("%" + title + "%").taskAssignee(dealUser).orderByTaskCreateTime().desc().listPage(pageRowStartNo, pageSize);
                        totalRowcnt = taskService.createTaskQuery().processInstanceBusinessKeyLike("%" + title + "%").taskAssignee(dealUser).count();
                    } else {
                        //获取该用户待办事项
                        taskPageList = taskService.createTaskQuery().processInstanceBusinessKeyLike("%" + title + "%").processDefinitionKeyIn(processDefineKeyList).taskAssignee(dealUser).orderByTaskCreateTime().desc().listPage(pageRowStartNo, pageSize);
                        totalRowcnt = taskService.createTaskQuery().processInstanceBusinessKeyLike("%" + title + "%").processDefinitionKeyIn(processDefineKeyList).taskAssignee(dealUser).count();
                    }
                }


                for (Task task : taskPageList) {

                    String processId = task.getProcessInstanceId();

                    if (processId == null) {
                        //说明是子任务，没有processid
                        Task parentTask = taskService.createTaskQuery().taskId(task.getParentTaskId()).singleResult();
                        processId = parentTask.getProcessInstanceId();
                    }
                    ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
                    ResponseSituationDto psd = new ResponseSituationDto();
                    psd.setCurrentTaskId(task.getId());
                    psd.setCurrentTaskName(task.getName());
                    psd.setCurrentTaskDefinitionKey(task.getTaskDefinitionKey());
                    psd.setProcessTitle(pi.getName());
                    psd.setProcessId(pi.getId());
                    psd.setProcessDefineName(pi.getProcessDefinitionName());
                    psd.setProcessDefineKey(pi.getProcessDefinitionKey());
                    psd.setStartTime(convertTime(pi.getStartTime()));
                    psd.setStartUsername(pi.getStartUserId());
                    psd.setStartUserChineseName(flowableEhrEmpService.getChineseName(pi.getStartUserId()));
                    psd.setCurrentAssignee(task.getAssignee());
                    psd.setCurrentAssigneeName(flowableEhrEmpService.getChineseName(task.getAssignee()));
                    psd.setSysid(pi.getTenantId());
                    psd.setStatus("0");
                    list.add(psd);

                }

                //   logger.info(list.toString());
            } else if (!StringUtils.isEmpty(startUser) || !StringUtils.isEmpty(involveUser) || !CollectionUtils.isEmpty(processDefineKeyList)) {
                //pi.getProcessDefinitionId();//Product:1:46aa53c6-0ec0-11ec-9532-000c299a9069
//            pi.getProcessDefinitionName();//产品成立流程
//            pi.getProcessDefinitionKey();//Product
//            pi.getProcessDefinitionVersion();//1
                //流程模板中文名为粒度
                //也可以按版本号或者key
                List<HistoricProcessInstance> hpis = new ArrayList<>();
                //根据模板中文名称查询全量包括已经结束的
//                if (!StringUtils.isEmpty(processDefineName)) {
//                    hpis = historyService.createHistoricProcessInstanceQuery().processDefinitionName(processDefineName).orderByProcessInstanceStartTime().desc().list();
//                } else if (!StringUtils.isEmpty(title)) {
//                    hpis = historyService.createHistoricProcessInstanceQuery()
//                            .processInstanceNameLike("%" + title + "%").orderByProcessInstanceStartTime().desc().list();
//                } else
                if (isSysid) {
                    if (!StringUtils.isEmpty(startUser)) {
                        if (!CollectionUtils.isEmpty(processDefineKeyList) && !StringUtils.isEmpty(title)) {
                            if (hasAll) {
                                hpis = historyService.createHistoricProcessInstanceQuery()
                                        .startedBy(startUser).processInstanceNameLike("%" + title + "%")
                                        .processDefinitionKeyIn(processDefineKeyList).startedBefore(end).startedAfter(begin).processInstanceTenantId(sysid).orderByProcessInstanceStartTime().desc().listPage(pageRowStartNo, pageSize);
                                totalRowcnt = historyService.createHistoricProcessInstanceQuery()
                                        .startedBy(startUser).processInstanceNameLike("%" + title + "%")
                                        .processDefinitionKeyIn(processDefineKeyList).startedBefore(end).startedAfter(begin).processInstanceTenantId(sysid).count();
                            } else {
                                if (hasEnd) {
                                    hpis = historyService.createHistoricProcessInstanceQuery().finished()
                                            .startedBy(startUser).processInstanceNameLike("%" + title + "%")
                                            .processDefinitionKeyIn(processDefineKeyList).startedBefore(end).startedAfter(begin).processInstanceTenantId(sysid).orderByProcessInstanceStartTime().desc().listPage(pageRowStartNo, pageSize);
                                    totalRowcnt = historyService.createHistoricProcessInstanceQuery().finished()
                                            .startedBy(startUser).processInstanceNameLike("%" + title + "%")
                                            .processDefinitionKeyIn(processDefineKeyList).startedBefore(end).startedAfter(begin).processInstanceTenantId(sysid).count();
                                } else {
                                    hpis = historyService.createHistoricProcessInstanceQuery().unfinished()
                                            .startedBy(startUser).processInstanceNameLike("%" + title + "%")
                                            .processDefinitionKeyIn(processDefineKeyList).startedBefore(end).startedAfter(begin).processInstanceTenantId(sysid).orderByProcessInstanceStartTime().desc().listPage(pageRowStartNo, pageSize);
                                    totalRowcnt = historyService.createHistoricProcessInstanceQuery().unfinished()
                                            .startedBy(startUser).processInstanceNameLike("%" + title + "%")
                                            .processDefinitionKeyIn(processDefineKeyList).startedBefore(end).startedAfter(begin).processInstanceTenantId(sysid).count();
                                }
                            }
                        } else if (!CollectionUtils.isEmpty(processDefineKeyList) && StringUtils.isEmpty(title)) {
                            if (hasAll) {
                                hpis = historyService.createHistoricProcessInstanceQuery()
                                        .startedBy(startUser).processDefinitionKeyIn(processDefineKeyList).startedBefore(end).startedAfter(begin).processInstanceTenantId(sysid)
                                        .orderByProcessInstanceStartTime().desc().listPage(pageRowStartNo, pageSize);
                                totalRowcnt = historyService.createHistoricProcessInstanceQuery()
                                        .startedBy(startUser).processDefinitionKeyIn(processDefineKeyList).startedBefore(end).startedAfter(begin).processInstanceTenantId(sysid).count();
                            } else {
                                if (hasEnd) {
                                    hpis = historyService.createHistoricProcessInstanceQuery().finished()
                                            .startedBy(startUser).processDefinitionKeyIn(processDefineKeyList).startedBefore(end).startedAfter(begin).processInstanceTenantId(sysid)
                                            .orderByProcessInstanceStartTime().desc().listPage(pageRowStartNo, pageSize);
                                    totalRowcnt = historyService.createHistoricProcessInstanceQuery().finished()
                                            .startedBy(startUser).processDefinitionKeyIn(processDefineKeyList).startedBefore(end).startedAfter(begin).processInstanceTenantId(sysid).count();
                                } else {
                                    hpis = historyService.createHistoricProcessInstanceQuery().unfinished()
                                            .startedBy(startUser).processDefinitionKeyIn(processDefineKeyList).startedBefore(end).startedAfter(begin).processInstanceTenantId(sysid)
                                            .orderByProcessInstanceStartTime().desc().listPage(pageRowStartNo, pageSize);
                                    totalRowcnt = historyService.createHistoricProcessInstanceQuery().unfinished()
                                            .startedBy(startUser).processDefinitionKeyIn(processDefineKeyList).startedBefore(end).startedAfter(begin).processInstanceTenantId(sysid).count();
                                }
                            }
                        } else if (CollectionUtils.isEmpty(processDefineKeyList) && !StringUtils.isEmpty(title)) {
                            if (hasAll) {
                                hpis = historyService.createHistoricProcessInstanceQuery()
                                        .startedBy(startUser).processInstanceNameLike("%" + title + "%").startedBefore(end).startedAfter(begin).processInstanceTenantId(sysid)
                                        .orderByProcessInstanceStartTime().desc().listPage(pageRowStartNo, pageSize);
                                totalRowcnt = historyService.createHistoricProcessInstanceQuery()
                                        .startedBy(startUser).processInstanceNameLike("%" + title + "%").startedBefore(end).startedAfter(begin).processInstanceTenantId(sysid).count();
                            } else {
                                if (hasEnd) {
                                    hpis = historyService.createHistoricProcessInstanceQuery().finished()
                                            .startedBy(startUser).processInstanceNameLike("%" + title + "%").startedBefore(end).startedAfter(begin).processInstanceTenantId(sysid)
                                            .orderByProcessInstanceStartTime().desc().listPage(pageRowStartNo, pageSize);
                                    totalRowcnt = historyService.createHistoricProcessInstanceQuery().finished()
                                            .startedBy(startUser).processInstanceNameLike("%" + title + "%").startedBefore(end).startedAfter(begin).processInstanceTenantId(sysid).count();
                                } else {
                                    hpis = historyService.createHistoricProcessInstanceQuery().unfinished()
                                            .startedBy(startUser).processInstanceNameLike("%" + title + "%").startedBefore(end).startedAfter(begin).processInstanceTenantId(sysid)
                                            .orderByProcessInstanceStartTime().desc().listPage(pageRowStartNo, pageSize);
                                    totalRowcnt = historyService.createHistoricProcessInstanceQuery().unfinished()
                                            .startedBy(startUser).processInstanceNameLike("%" + title + "%").startedBefore(end).startedAfter(begin).processInstanceTenantId(sysid).count();
                                }
                            }
                        } else {
                            if (hasAll) {
                                hpis = historyService.createHistoricProcessInstanceQuery()
                                        .startedBy(startUser).startedBefore(end).startedAfter(begin).processInstanceTenantId(sysid).orderByProcessInstanceStartTime().desc().listPage(pageRowStartNo, pageSize);
                                totalRowcnt = historyService.createHistoricProcessInstanceQuery().startedBefore(end).startedAfter(begin)
                                        .startedBy(startUser).processInstanceTenantId(sysid).count();
                            } else {
                                if (hasEnd) {
                                    hpis = historyService.createHistoricProcessInstanceQuery().finished()
                                            .startedBy(startUser).startedBefore(end).startedAfter(begin).processInstanceTenantId(sysid).orderByProcessInstanceStartTime().desc().listPage(pageRowStartNo, pageSize);
                                    totalRowcnt = historyService.createHistoricProcessInstanceQuery().finished().startedBefore(end).startedAfter(begin)
                                            .startedBy(startUser).processInstanceTenantId(sysid).count();
                                } else {
                                    hpis = historyService.createHistoricProcessInstanceQuery().unfinished()
                                            .startedBy(startUser).startedBefore(end).startedAfter(begin).processInstanceTenantId(sysid).orderByProcessInstanceStartTime().desc().listPage(pageRowStartNo, pageSize);
                                    totalRowcnt = historyService.createHistoricProcessInstanceQuery().unfinished().startedBefore(end).startedAfter(begin)
                                            .startedBy(startUser).processInstanceTenantId(sysid).count();
                                }
                            }
                        }

                    } else if (!StringUtils.isEmpty(involveUser)) {

//                        if (!StringUtils.isEmpty(processDefineKey) && !StringUtils.isEmpty(title)) {
//                            hpis = historyService.createHistoricProcessInstanceQuery()
//                                    .involvedUser(involveUser).processInstanceNameLike("%" + title + "%")
//                                    .processDefinitionKey(processDefineKey).startedBefore(end).startedAfter(begin).processInstanceTenantId(sysid).orderByProcessInstanceStartTime().desc().listPage(pageRowStartNo, pageSize);
//                            totalRowcnt = historyService.createHistoricProcessInstanceQuery()
//                                    .involvedUser(involveUser).processInstanceNameLike("%" + title + "%")
//                                    .processDefinitionKey(processDefineKey).startedBefore(end).startedAfter(begin).processInstanceTenantId(sysid).count();
//                        } else if (!StringUtils.isEmpty(processDefineKey) && StringUtils.isEmpty(title)) {
//                            hpis = historyService.createHistoricProcessInstanceQuery()
//                                    .involvedUser(involveUser).processDefinitionKey(processDefineKey).startedBefore(end).startedAfter(begin).processInstanceTenantId(sysid)
//                                    .orderByProcessInstanceStartTime().desc().listPage(pageRowStartNo, pageSize);
//                            totalRowcnt = historyService.createHistoricProcessInstanceQuery()
//                                    .involvedUser(involveUser).processDefinitionKey(processDefineKey).startedBefore(end).startedAfter(begin).processInstanceTenantId(sysid).count();
//                        } else if (StringUtils.isEmpty(processDefineKey) && !StringUtils.isEmpty(title)) {
//                            hpis = historyService.createHistoricProcessInstanceQuery()
//                                    .involvedUser(involveUser).processInstanceNameLike("%" + title + "%").startedBefore(end).startedAfter(begin).processInstanceTenantId(sysid)
//                                    .orderByProcessInstanceStartTime().desc().listPage(pageRowStartNo, pageSize);
//                            totalRowcnt = historyService.createHistoricProcessInstanceQuery()
//                                    .involvedUser(involveUser).processInstanceNameLike("%" + title + "%").startedBefore(end).startedAfter(begin).processInstanceTenantId(sysid).count();
//                        } else {
//                            hpis = historyService.createHistoricProcessInstanceQuery()
//                                    .involvedUser(involveUser).startedBefore(end).startedAfter(begin).processInstanceTenantId(sysid).orderByProcessInstanceStartTime().desc().listPage(pageRowStartNo, pageSize);
//                            totalRowcnt = historyService.createHistoricProcessInstanceQuery().involvedUser(involveUser).startedBefore(end).startedAfter(begin).processInstanceTenantId(sysid).count();
//                        }

                        String processDefineKeyStr = null;
                        if (CollectionUtils.isEmpty(processDefineKeyList)) {
                            //  processDefineKeyList = null;
                        } else {
                            processDefineKeyStr = String.join(",", processDefineKeyList);
                        }

                        if (StringUtils.isEmpty(title)) {
                            title = null;
                        }
                        if (StringUtils.isEmpty(sysid)) {
                            sysid = null;
                        }
                        String hasEndForInvolve = null;
                        if (!hasAll) {
                            if (hasEnd) {
                                hasEndForInvolve = "1";
                            } else {
                                hasEndForInvolve = "0";
                            }
                        }
                        Page<List<Map<String, String>>> done = flowableCommonService.findUserDone(involveUser, processDefineKeyStr, processDefineKeyList, title, begin, end, sysid, hasEndForInvolve, null, pageable);
                        logger.info(String.valueOf(done.stream().count()));

                        for (Object row : done.getContent()) {
                            Map<String, Object> rowColMap = (Map<String, Object>) row;
                            HistoricProcessInstanceEntityImpl hp = new HistoricProcessInstanceEntityImpl();
                            hp.setName(rowColMap.get("title").toString());

                            String defineName = "";
                            if (rowColMap.get("processDefinitionId").toString().contains(":")) {
                                ProcessDefinition ss = repositoryService.createProcessDefinitionQuery().processDefinitionKey(rowColMap.get("processDefinitionId").toString().split(":")[0]).orderByProcessDefinitionVersion().desc().list().get(0);
                                defineName = ss.getName();
                            } else if (rowColMap.get("businessKey") != null) {
                                ProcessDefinition ss = repositoryService.createProcessDefinitionQuery().processDefinitionKey(rowColMap.get("businessKey").toString().split("\\.")[0]).orderByProcessDefinitionVersion().desc().list().get(0);
                                defineName = ss.getName();
                            }
                            hp.setProcessDefinitionName(defineName);
                            hp.setStartUserId(rowColMap.get("startUserId").toString());
                            hp.setTenantId(rowColMap.get("tenantId").toString());
                            hp.setStartTime((Date) rowColMap.get("startTime"));
                            hp.setProcessInstanceId(rowColMap.get("processInstanceId").toString());
                            hp.setId(rowColMap.get("processInstanceId").toString());

                            hpis.add(hp);
                        }
                        totalRowcnt = done.getTotalElements();
                    } else {
                        if (!CollectionUtils.isEmpty(processDefineKeyList) && !StringUtils.isEmpty(title)) {
                            if (hasAll) {
                                hpis = historyService.createHistoricProcessInstanceQuery().processInstanceNameLike("%" + title + "%")
                                        .processDefinitionKeyIn(processDefineKeyList).startedBefore(end).startedAfter(begin).processInstanceTenantId(sysid).orderByProcessInstanceStartTime().desc().listPage(pageRowStartNo, pageSize);
                                totalRowcnt = historyService.createHistoricProcessInstanceQuery().processInstanceNameLike("%" + title + "%")
                                        .processDefinitionKeyIn(processDefineKeyList).startedBefore(end).startedAfter(begin).processInstanceTenantId(sysid).count();
                            } else {
                                if (hasEnd) {
                                    hpis = historyService.createHistoricProcessInstanceQuery().processInstanceNameLike("%" + title + "%").finished()
                                            .processDefinitionKeyIn(processDefineKeyList).startedBefore(end).startedAfter(begin).processInstanceTenantId(sysid).orderByProcessInstanceStartTime().desc().listPage(pageRowStartNo, pageSize);
                                    totalRowcnt = historyService.createHistoricProcessInstanceQuery().processInstanceNameLike("%" + title + "%").finished()
                                            .processDefinitionKeyIn(processDefineKeyList).startedBefore(end).startedAfter(begin).processInstanceTenantId(sysid).count();
                                } else {
                                    hpis = historyService.createHistoricProcessInstanceQuery().processInstanceNameLike("%" + title + "%").unfinished()
                                            .processDefinitionKeyIn(processDefineKeyList).startedBefore(end).startedAfter(begin).processInstanceTenantId(sysid).orderByProcessInstanceStartTime().desc().listPage(pageRowStartNo, pageSize);
                                    totalRowcnt = historyService.createHistoricProcessInstanceQuery().processInstanceNameLike("%" + title + "%").unfinished()
                                            .processDefinitionKeyIn(processDefineKeyList).startedBefore(end).startedAfter(begin).processInstanceTenantId(sysid).count();
                                }
                            }
                        } else if (!CollectionUtils.isEmpty(processDefineKeyList) && StringUtils.isEmpty(title)) {
                            if (hasAll) {
                                hpis = historyService.createHistoricProcessInstanceQuery().processDefinitionKeyIn(processDefineKeyList).startedBefore(end).startedAfter(begin).processInstanceTenantId(sysid)
                                        .orderByProcessInstanceStartTime().desc().listPage(pageRowStartNo, pageSize);
                                totalRowcnt = historyService.createHistoricProcessInstanceQuery().processDefinitionKeyIn(processDefineKeyList).startedBefore(end).startedAfter(begin).processInstanceTenantId(sysid).count();
                            } else {
                                if (hasEnd) {
                                    hpis = historyService.createHistoricProcessInstanceQuery().finished().processDefinitionKeyIn(processDefineKeyList).startedBefore(end).startedAfter(begin).processInstanceTenantId(sysid)
                                            .orderByProcessInstanceStartTime().desc().listPage(pageRowStartNo, pageSize);
                                    totalRowcnt = historyService.createHistoricProcessInstanceQuery().finished().processDefinitionKeyIn(processDefineKeyList).startedBefore(end).startedAfter(begin).processInstanceTenantId(sysid).count();
                                } else {
                                    hpis = historyService.createHistoricProcessInstanceQuery().unfinished().processDefinitionKeyIn(processDefineKeyList).startedBefore(end).startedAfter(begin).processInstanceTenantId(sysid)
                                            .orderByProcessInstanceStartTime().desc().listPage(pageRowStartNo, pageSize);
                                    totalRowcnt = historyService.createHistoricProcessInstanceQuery().unfinished().processDefinitionKeyIn(processDefineKeyList).startedBefore(end).startedAfter(begin).processInstanceTenantId(sysid).count();
                                }
                            }
                        }
                    }
                } else {
                    if (!StringUtils.isEmpty(startUser)) {
                        if (!CollectionUtils.isEmpty(processDefineKeyList) && !StringUtils.isEmpty(title)) {
                            if (hasAll) {
                                hpis = historyService.createHistoricProcessInstanceQuery()
                                        .startedBy(startUser).processInstanceNameLike("%" + title + "%")
                                        .processDefinitionKeyIn(processDefineKeyList).startedBefore(end).startedAfter(begin).orderByProcessInstanceStartTime().desc().listPage(pageRowStartNo, pageSize);
                                totalRowcnt = historyService.createHistoricProcessInstanceQuery()
                                        .startedBy(startUser).processInstanceNameLike("%" + title + "%")
                                        .processDefinitionKeyIn(processDefineKeyList).startedBefore(end).startedAfter(begin).count();
                            } else {
                                if (hasEnd) {
                                    hpis = historyService.createHistoricProcessInstanceQuery().finished()
                                            .startedBy(startUser).processInstanceNameLike("%" + title + "%")
                                            .processDefinitionKeyIn(processDefineKeyList).startedBefore(end).startedAfter(begin).orderByProcessInstanceStartTime().desc().listPage(pageRowStartNo, pageSize);
                                    totalRowcnt = historyService.createHistoricProcessInstanceQuery().finished()
                                            .startedBy(startUser).processInstanceNameLike("%" + title + "%")
                                            .processDefinitionKeyIn(processDefineKeyList).startedBefore(end).startedAfter(begin).count();
                                } else {
                                    hpis = historyService.createHistoricProcessInstanceQuery().unfinished()
                                            .startedBy(startUser).processInstanceNameLike("%" + title + "%")
                                            .processDefinitionKeyIn(processDefineKeyList).startedBefore(end).startedAfter(begin).orderByProcessInstanceStartTime().desc().listPage(pageRowStartNo, pageSize);
                                    totalRowcnt = historyService.createHistoricProcessInstanceQuery().unfinished()
                                            .startedBy(startUser).processInstanceNameLike("%" + title + "%")
                                            .processDefinitionKeyIn(processDefineKeyList).startedBefore(end).startedAfter(begin).count();
                                }
                            }
                        } else if (!CollectionUtils.isEmpty(processDefineKeyList) && StringUtils.isEmpty(title)) {
                            if (hasAll) {
                                hpis = historyService.createHistoricProcessInstanceQuery()
                                        .startedBy(startUser).processDefinitionKeyIn(processDefineKeyList).startedBefore(end).startedAfter(begin)
                                        .orderByProcessInstanceStartTime().desc().listPage(pageRowStartNo, pageSize);
                                totalRowcnt = historyService.createHistoricProcessInstanceQuery()
                                        .startedBy(startUser).processDefinitionKeyIn(processDefineKeyList).startedBefore(end).startedAfter(begin).count();
                            } else {
                                if (hasEnd) {
                                    hpis = historyService.createHistoricProcessInstanceQuery().finished()
                                            .startedBy(startUser).processDefinitionKeyIn(processDefineKeyList).startedBefore(end).startedAfter(begin)
                                            .orderByProcessInstanceStartTime().desc().listPage(pageRowStartNo, pageSize);
                                    totalRowcnt = historyService.createHistoricProcessInstanceQuery().finished()
                                            .startedBy(startUser).processDefinitionKeyIn(processDefineKeyList).startedBefore(end).startedAfter(begin).count();
                                } else {
                                    hpis = historyService.createHistoricProcessInstanceQuery().unfinished()
                                            .startedBy(startUser).processDefinitionKeyIn(processDefineKeyList).startedBefore(end).startedAfter(begin)
                                            .orderByProcessInstanceStartTime().desc().listPage(pageRowStartNo, pageSize);
                                    totalRowcnt = historyService.createHistoricProcessInstanceQuery().unfinished()
                                            .startedBy(startUser).processDefinitionKeyIn(processDefineKeyList).startedBefore(end).startedAfter(begin).count();
                                }
                            }
                        } else if (CollectionUtils.isEmpty(processDefineKeyList) && !StringUtils.isEmpty(title)) {
                            if (hasAll) {
                                hpis = historyService.createHistoricProcessInstanceQuery()
                                        .startedBy(startUser).processInstanceNameLike("%" + title + "%").startedBefore(end).startedAfter(begin)
                                        .orderByProcessInstanceStartTime().desc().listPage(pageRowStartNo, pageSize);
                                totalRowcnt = historyService.createHistoricProcessInstanceQuery()
                                        .startedBy(startUser).processInstanceNameLike("%" + title + "%").startedBefore(end).startedAfter(begin).count();
                            } else {
                                if (hasEnd) {
                                    hpis = historyService.createHistoricProcessInstanceQuery().finished()
                                            .startedBy(startUser).processInstanceNameLike("%" + title + "%").startedBefore(end).startedAfter(begin)
                                            .orderByProcessInstanceStartTime().desc().listPage(pageRowStartNo, pageSize);
                                    totalRowcnt = historyService.createHistoricProcessInstanceQuery().finished()
                                            .startedBy(startUser).processInstanceNameLike("%" + title + "%").startedBefore(end).startedAfter(begin).count();
                                } else {
                                    hpis = historyService.createHistoricProcessInstanceQuery().unfinished()
                                            .startedBy(startUser).processInstanceNameLike("%" + title + "%").startedBefore(end).startedAfter(begin)
                                            .orderByProcessInstanceStartTime().desc().listPage(pageRowStartNo, pageSize);
                                    totalRowcnt = historyService.createHistoricProcessInstanceQuery().unfinished()
                                            .startedBy(startUser).processInstanceNameLike("%" + title + "%").startedBefore(end).startedAfter(begin).count();
                                }
                            }
                        } else {
                            if (hasAll) {
                                hpis = historyService.createHistoricProcessInstanceQuery()
                                        .startedBy(startUser).startedBefore(end).startedAfter(begin).orderByProcessInstanceStartTime().desc().listPage(pageRowStartNo, pageSize);
                                totalRowcnt = historyService.createHistoricProcessInstanceQuery().startedBefore(end).startedAfter(begin)
                                        .startedBy(startUser).count();
                            } else {
                                if (hasEnd) {
                                    hpis = historyService.createHistoricProcessInstanceQuery().finished()
                                            .startedBy(startUser).startedBefore(end).startedAfter(begin).orderByProcessInstanceStartTime().desc().listPage(pageRowStartNo, pageSize);
                                    totalRowcnt = historyService.createHistoricProcessInstanceQuery().finished().startedBefore(end).startedAfter(begin)
                                            .startedBy(startUser).count();
                                } else {
                                    hpis = historyService.createHistoricProcessInstanceQuery().unfinished()
                                            .startedBy(startUser).startedBefore(end).startedAfter(begin).orderByProcessInstanceStartTime().desc().listPage(pageRowStartNo, pageSize);
                                    totalRowcnt = historyService.createHistoricProcessInstanceQuery().unfinished().startedBefore(end).startedAfter(begin)
                                            .startedBy(startUser).count();
                                }
                            }
                        }

                    } else if (!StringUtils.isEmpty(involveUser)) {

//                        if (!StringUtils.isEmpty(processDefineKey) && !StringUtils.isEmpty(title)) {
//                            hpis = historyService.createHistoricProcessInstanceQuery()
//                                    .involvedUser(involveUser).processInstanceNameLike("%" + title + "%")
//                                    .processDefinitionKey(processDefineKey).startedBefore(end).startedAfter(begin).orderByProcessInstanceStartTime().desc().listPage(pageRowStartNo, pageSize);
//                            totalRowcnt = historyService.createHistoricProcessInstanceQuery()
//                                    .involvedUser(involveUser).processInstanceNameLike("%" + title + "%")
//                                    .processDefinitionKey(processDefineKey).startedBefore(end).startedAfter(begin).count();
//                        } else if (!StringUtils.isEmpty(processDefineKey) && StringUtils.isEmpty(title)) {
//                            hpis = historyService.createHistoricProcessInstanceQuery()
//                                    .involvedUser(involveUser).processDefinitionKey(processDefineKey).startedBefore(end).startedAfter(begin)
//                                    .orderByProcessInstanceStartTime().desc().listPage(pageRowStartNo, pageSize);
//                            totalRowcnt = historyService.createHistoricProcessInstanceQuery()
//                                    .involvedUser(involveUser).processDefinitionKey(processDefineKey).startedBefore(end).startedAfter(begin).count();
//                        } else if (StringUtils.isEmpty(processDefineKey) && !StringUtils.isEmpty(title)) {
//                            hpis = historyService.createHistoricProcessInstanceQuery()
//                                    .involvedUser(involveUser).processInstanceNameLike("%" + title + "%").startedBefore(end).startedAfter(begin)
//                                    .orderByProcessInstanceStartTime().desc().listPage(pageRowStartNo, pageSize);
//                            totalRowcnt = historyService.createHistoricProcessInstanceQuery()
//                                    .involvedUser(involveUser).processInstanceNameLike("%" + title + "%").startedBefore(end).startedAfter(begin).count();
//                        } else {
//                            hpis = historyService.createHistoricProcessInstanceQuery()
//                                    .involvedUser(involveUser).startedBefore(end).startedAfter(begin).orderByProcessInstanceStartTime().desc().listPage(pageRowStartNo, pageSize);
//                            totalRowcnt = historyService.createHistoricProcessInstanceQuery().involvedUser(involveUser).startedBefore(end).startedAfter(begin).count();
//                        }

                        String processDefineKeyStr = null;
                        if (CollectionUtils.isEmpty(processDefineKeyList)) {
                            //  processDefineKeyList = null;
                        } else {
                            processDefineKeyStr = String.join(",", processDefineKeyList);
                        }
                        if (StringUtils.isEmpty(title)) {
                            title = null;
                        }
                        if (StringUtils.isEmpty(sysid)) {
                            sysid = null;
                        }
                        String hasEndForInvolve = null;
                        if (!hasAll) {
                            if (hasEnd) {
                                hasEndForInvolve = "1";
                            } else {
                                hasEndForInvolve = "0";
                            }
                        }
                        Page<List<Map<String, String>>> done = flowableCommonService.findUserDone(involveUser, processDefineKeyStr, processDefineKeyList, title, begin, end, sysid, hasEndForInvolve, null, pageable);
                        logger.info(String.valueOf(done.stream().count()));

                        for (Object row : done.getContent()) {
                            Map<String, Object> rowColMap = (Map<String, Object>) row;
                            HistoricProcessInstanceEntityImpl hp = new HistoricProcessInstanceEntityImpl();
                            hp.setName(rowColMap.get("title").toString());

                            String defineName = "";
                            if (rowColMap.get("processDefinitionId").toString().contains(":")) {
                                ProcessDefinition ss = repositoryService.createProcessDefinitionQuery().processDefinitionKey(rowColMap.get("processDefinitionId").toString().split(":")[0]).orderByProcessDefinitionVersion().desc().list().get(0);
                                defineName = ss.getName();
                            } else if (rowColMap.get("businessKey") != null) {
                                ProcessDefinition ss = repositoryService.createProcessDefinitionQuery().processDefinitionKey(rowColMap.get("businessKey").toString().split("\\.")[0]).orderByProcessDefinitionVersion().desc().list().get(0);
                                defineName = ss.getName();
                            }

                            hp.setProcessDefinitionName(defineName);
                            hp.setStartUserId(rowColMap.get("startUserId").toString());
                            hp.setTenantId(rowColMap.get("tenantId").toString());
                            hp.setStartTime((Date) rowColMap.get("startTime"));
                            hp.setProcessInstanceId(rowColMap.get("processInstanceId").toString());
                            hp.setId(rowColMap.get("processInstanceId").toString());

                            hpis.add(hp);
                        }
                        totalRowcnt = done.getTotalElements();
                    } else {
                        if (!CollectionUtils.isEmpty(processDefineKeyList) && !StringUtils.isEmpty(title)) {
                            if (hasAll) {
                                hpis = historyService.createHistoricProcessInstanceQuery().processInstanceNameLike("%" + title + "%")
                                        .processDefinitionKeyIn(processDefineKeyList).startedBefore(end).startedAfter(begin).orderByProcessInstanceStartTime().desc().listPage(pageRowStartNo, pageSize);
                                totalRowcnt = historyService.createHistoricProcessInstanceQuery().processInstanceNameLike("%" + title + "%")
                                        .processDefinitionKeyIn(processDefineKeyList).startedBefore(end).startedAfter(begin).count();
                            } else {
                                if (hasEnd) {
                                    hpis = historyService.createHistoricProcessInstanceQuery().finished().processInstanceNameLike("%" + title + "%")
                                            .processDefinitionKeyIn(processDefineKeyList).startedBefore(end).startedAfter(begin).orderByProcessInstanceStartTime().desc().listPage(pageRowStartNo, pageSize);
                                    totalRowcnt = historyService.createHistoricProcessInstanceQuery().finished().processInstanceNameLike("%" + title + "%")
                                            .processDefinitionKeyIn(processDefineKeyList).startedBefore(end).startedAfter(begin).count();
                                } else {
                                    hpis = historyService.createHistoricProcessInstanceQuery().unfinished().processInstanceNameLike("%" + title + "%")
                                            .processDefinitionKeyIn(processDefineKeyList).startedBefore(end).startedAfter(begin).orderByProcessInstanceStartTime().desc().listPage(pageRowStartNo, pageSize);
                                    totalRowcnt = historyService.createHistoricProcessInstanceQuery().unfinished().processInstanceNameLike("%" + title + "%")
                                            .processDefinitionKeyIn(processDefineKeyList).startedBefore(end).startedAfter(begin).count();
                                }
                            }
                        } else if (!CollectionUtils.isEmpty(processDefineKeyList) && StringUtils.isEmpty(title)) {
                            if (hasAll) {
                                hpis = historyService.createHistoricProcessInstanceQuery().processDefinitionKeyIn(processDefineKeyList).startedBefore(end).startedAfter(begin)
                                        .orderByProcessInstanceStartTime().desc().listPage(pageRowStartNo, pageSize);
                                totalRowcnt = historyService.createHistoricProcessInstanceQuery().processDefinitionKeyIn(processDefineKeyList).startedBefore(end).startedAfter(begin).count();
                            } else {
                                if (hasEnd) {
                                    hpis = historyService.createHistoricProcessInstanceQuery().finished().processDefinitionKeyIn(processDefineKeyList).startedBefore(end).startedAfter(begin)
                                            .orderByProcessInstanceStartTime().desc().listPage(pageRowStartNo, pageSize);
                                    totalRowcnt = historyService.createHistoricProcessInstanceQuery().finished().processDefinitionKeyIn(processDefineKeyList).startedBefore(end).startedAfter(begin).count();
                                } else {
                                    hpis = historyService.createHistoricProcessInstanceQuery().unfinished().processDefinitionKeyIn(processDefineKeyList).startedBefore(end).startedAfter(begin)
                                            .orderByProcessInstanceStartTime().desc().listPage(pageRowStartNo, pageSize);
                                    totalRowcnt = historyService.createHistoricProcessInstanceQuery().unfinished().processDefinitionKeyIn(processDefineKeyList).startedBefore(end).startedAfter(begin).count();
                                }
                            }
                        }
                    }
                }


                List<Task> tasklist = new ArrayList<>();
                for (HistoricProcessInstance pi : hpis) {
                    ResponseSituationDto psd = new ResponseSituationDto();
                    List<CurrentTaskInfoDto> currentTaskInfoDtoList = new ArrayList<>();
                    psd.setStatus("0");
                    if (isSysid) {
                        //如果参数带系统名称，则过滤掉带租户的流程
//                        if (!sysid.equals(pi.getTenantId())) {
//                            continue;
//                        }
                        if (!CollectionUtils.isEmpty(processDefineKeyList)) {
                            //获取该模板的流程
                            tasklist = taskService.createTaskQuery().processDefinitionKeyIn(processDefineKeyList).processInstanceId(pi.getId()).taskTenantId(sysid).orderByTaskCreateTime().desc().list();
                        } else {
                            //其他
                            tasklist = taskService.createTaskQuery().processInstanceId(pi.getId()).taskTenantId(sysid).orderByTaskCreateTime().desc().list();
                        }
                    } else {
                        if (!CollectionUtils.isEmpty(processDefineKeyList)) {
                            tasklist = taskService.createTaskQuery().processDefinitionKeyIn(processDefineKeyList).processInstanceId(pi.getId()).orderByTaskCreateTime().desc().list();
                        } else {
                            tasklist = taskService.createTaskQuery().processInstanceId(pi.getId()).orderByTaskCreateTime().desc().list();
                        }
                    }

                    //如果流程没结束，查询到任务节点
                    if (!checkProcessEnd(pi.getId())) {
                        if (tasklist != null && tasklist.size() > 0) {
                            Map<String, List<String>> map = new HashMap<String, List<String>>();
                            Map<String, List<String>> taskidmap = new HashMap<String, List<String>>();

                            StringBuffer sbname = new StringBuffer();
                            StringBuffer sbkey = new StringBuffer();
                            StringBuffer sbid = new StringBuffer();
                            StringBuffer sbassignee = new StringBuffer();
                            for (int i = 0; i < tasklist.size(); i++) {
                                if (i != (tasklist.size() - 1)) {
                                    sbkey.append(tasklist.get(i).getTaskDefinitionKey() + "|");
                                    sbname.append(tasklist.get(i).getName() + "|");
                                    sbassignee.append(tasklist.get(i).getAssignee() + "|");
                                    sbid.append(tasklist.get(i).getId() + "|");

                                    String key = tasklist.get(i).getTaskDefinitionKey() + "|" + tasklist.get(i).getName();
                                    List<String> assigneeList = new ArrayList<>();
                                    List<String> taskIdList = new ArrayList<>();
                                    if (map.get(key) != null) {
                                        assigneeList = map.get(key);
                                    }
                                    assigneeList.add(tasklist.get(i).getAssignee());
                                    map.put(key, assigneeList);

                                    if (taskidmap.get(key) != null) {
                                        taskIdList = taskidmap.get(key);
                                    }
                                    taskIdList.add(tasklist.get(i).getId());
                                    taskidmap.put(key, taskIdList);
                                } else {
                                    sbkey.append(tasklist.get(i).getTaskDefinitionKey());
                                    sbname.append(tasklist.get(i).getName());
                                    sbassignee.append(tasklist.get(i).getAssignee());
                                    sbid.append(tasklist.get(i).getId());

                                    String key = tasklist.get(i).getTaskDefinitionKey() + "|" + tasklist.get(i).getName();
                                    List<String> assigneeList = new ArrayList<>();
                                    List<String> taskIdList = new ArrayList<>();
                                    if (map.get(key) != null) {
                                        assigneeList = map.get(key);
                                    }
                                    assigneeList.add(tasklist.get(i).getAssignee());
                                    map.put(key, assigneeList);

                                    if (taskidmap.get(key) != null) {
                                        taskIdList = taskidmap.get(key);
                                    }
                                    taskIdList.add(tasklist.get(i).getId());
                                    taskidmap.put(key, taskIdList);
                                }


                            }
                            psd.setCurrentTaskDefinitionKey(sbkey.toString());
                            psd.setCurrentTaskName(sbname.toString());
                            psd.setCurrentTaskId(sbid.toString());
                            psd.setCurrentAssignee(sbassignee.toString());
                            psd.setCurrentAssigneeName(flowableEhrEmpService.getChineseNameAll(sbassignee.toString(), "|"));

                            for (Map.Entry<String, List<String>> m : map.entrySet()) {
                                List<String> userid = m.getValue();
                                List<String> username = new ArrayList<>();
                                for (String id : userid) {
                                    username.add(flowableEhrEmpService.getChineseName(id));
                                }

                                String[] defname = m.getKey().split("\\|");
                                CurrentTaskInfoDto currentTaskInfoDto = new CurrentTaskInfoDto();
                                currentTaskInfoDto.setCurrentTaskName(defname[1]);
                                currentTaskInfoDto.setCurrentTaskDefinitionKey(defname[0]);
                                currentTaskInfoDto.setCurrentAssigneeList(m.getValue());
                                currentTaskInfoDto.setCurrentAssigneeNameList(username);
                                currentTaskInfoDto.setCurrentTaskIdList(taskidmap.get(m.getKey()));
                                currentTaskInfoDtoList.add(currentTaskInfoDto);
                            }

                        } else {
                            //流程未结束，且还有任务未完成，说明是其他sysid的流程，跳过
                            //continue;
                        }
                    } else {
                        psd.setStatus("1");
                        List<FlowableDetail> delist = flowableDetailService.findDetailByProcessId(pi.getId());
                        if (delist != null && delist.size() > 0) {
                            String status = delist.get(0).getProcessStatus();
                            //status2为stop手动结束，置状态
                            //status3为delete，不会出现在这个接口
                            if (("2").equals(status)) {
                                psd.setStatus("2");
                            }
                        }
                    }
                    psd.setProcessTitle(pi.getName());
                    psd.setProcessId(pi.getId());
                    psd.setProcessDefineName(pi.getProcessDefinitionName());
                    ProcessInstance p = runtimeService.createProcessInstanceQuery().processInstanceId(pi.getId()).singleResult();
                    if (p == null) {
                        HistoricProcessInstance hp = historyService.createHistoricProcessInstanceQuery().processInstanceId(pi.getId()).singleResult();
                        if (hp != null) {
                            psd.setProcessDefineKey(hp.getProcessDefinitionKey());
                        }
                    } else {
                        psd.setProcessDefineKey(p.getProcessDefinitionKey());
                    }

                    psd.setStartTime(convertTime(pi.getStartTime()));
                    if (pi.getEndTime() != null) {//如果流程结束，则返回流程结束时间
                        psd.setEndTime(convertTime(pi.getEndTime()));
                    }
                    psd.setStartUsername(pi.getStartUserId());
                    psd.setStartUserChineseName(flowableEhrEmpService.getChineseName(pi.getStartUserId()));
                    psd.setSysid(pi.getTenantId());

                    psd.setCurrentTaskInfoDtoList(currentTaskInfoDtoList);
                    list.add(psd);
                }
                //    logger.info(list.toString());
            }

            PageDataResult pageDataResult = new PageDataResult();
            pageDataResult.setList(list);
            pageDataResult.setTotals(totalRowcnt.intValue());
//            Page page = new PageImpl<ProcessSituationDto>(list, pageable, totalRowcnt);
            return FlowableResponse.success(pageDataResult);

        } catch (Exception e) {
            logger.error("flowable流程查询流程实例列表参数错误！", e);
            return FlowableResponse.error("flowable流程查询流程实例列表参数错误! e.getMessage=" + e.getMessage());
        }
    }


    /**
     * 查询流程实例列表
     * 统一入口
     */
    @RequestMapping(method = RequestMethod.POST, value = "/searchProcessListNew")
    @ApiOperation(value = "查询流程实例列表", notes = "查询流程实例列表统一入口")
    public FlowableResponse<PageDataResult<ResponseSituationDto>> searchProcessListNew(@RequestParam(value = "pageNum") Integer pageNum,
                                                                                       @RequestParam(value = "pageSize") Integer pageSize,
                                                                                       @RequestBody ParamSearchDto params) {

        try {
            Pageable pageable = PageRequest.of(PageUtil.initPageNo(pageNum) - 1, PageUtil.initPageSize(pageSize));

            boolean hasAll = true;
            boolean hasEnd = true;

            if (params.getHasProcessEnd() != null && !"".equals(params.getHasProcessEnd())) {
                if ("1".equals(params.getHasProcessEnd())) {
                    hasAll = false;
                    hasEnd = true;
                } else {
                    hasAll = false;
                    hasEnd = false;
                }
            }
            logger.info("查询流程实例列表 参数params={},{}-{}", params, pageNum, pageSize);

            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
            Date begin = null;
            Date end = null;
            if (!"".equals(params.getBeginDate()) && params.getBeginDate() != null) {
                begin = sdf.parse(params.getBeginDate());
            }
            if (!"".equals(params.getEndDate()) && params.getEndDate() != null) {
                end = sdf.parse(params.getEndDate());
                //解决流程结束时间查询不正确的问题
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(end);
                calendar.add(Calendar.DATE, 1);
                end = calendar.getTime();
            }

            //人员传参要么不传 要么只能传一个
            String title = params.getTitle();
            String startUser = params.getStartUser();
            String dealUser = params.getDealUser();
            String processDefineKeyOrig = params.getProcessDefineKey();
            String sysid = params.getSysid();
            String involveUser = params.getInvolveUser();

            int num = 0;
            if (!StringUtils.isEmpty(startUser)) {
                num++;
            }
            if (!StringUtils.isEmpty(dealUser)) {
                num++;
            }
            if (!StringUtils.isEmpty(involveUser)) {
                num++;
            }
            if (num > 1) {
                logger.error("flowable流程查询流程实例列表参数错误！");
                return FlowableResponse.error("flowable流程查询流程实例列表参数错误！");
            }
            if (num == 0 && StringUtils.isEmpty(processDefineKeyOrig)) {
                logger.error("flowable流程查询流程实例列表没有人员作为参数的时候，processDefineKey必填！");
                return FlowableResponse.error("flowable流程查询流程实例列表没有人员作为参数的时候，processDefineKey必填！");
            }

            List<String> processDefineKeyList = new ArrayList<>();
            if (!StringUtils.isEmpty(processDefineKeyOrig)) {
                String[] tmp = processDefineKeyOrig.split(",");
                for (String t : tmp) {
                    processDefineKeyList.add(t);
                }
            }

            boolean isSysid = true;
            if (StringUtils.isEmpty(sysid)) {
                isSysid = false;
            }
            //组装dto展示
            List<ResponseSituationDto> list = new ArrayList<>();

            //开始行
            Integer pageRowStartNo = ((Long) pageable.getOffset()).intValue();
            Long totalRowcnt = 0L;


            //查询待办
            if (!StringUtils.isEmpty(dealUser)) {
                List<Task> taskPageList = new ArrayList<>();

                TaskQuery rowsDataQuery = taskService.createTaskQuery();
                TaskQuery rowsCountQuery = taskService.createTaskQuery();
                if (isSysid) {
                    rowsDataQuery = rowsDataQuery.taskTenantId(sysid);
                    rowsCountQuery = rowsDataQuery.taskTenantId(sysid);
                }
                if (StrUtil.isNotEmpty(dealUser)) {
                    rowsDataQuery = rowsDataQuery.taskAssignee(dealUser);
                    rowsCountQuery = rowsDataQuery.taskAssignee(dealUser);
                }
                if (CollectionUtils.isNotEmpty(processDefineKeyList)) {
                    rowsDataQuery = rowsDataQuery.processDefinitionKeyIn(processDefineKeyList);
                    rowsCountQuery = rowsDataQuery.processDefinitionKeyIn(processDefineKeyList);
                }
                if (StrUtil.isNotEmpty(title)) {
                    rowsDataQuery = rowsDataQuery.processInstanceBusinessKeyLike("%" + title + "%");
                    rowsCountQuery = rowsDataQuery.processInstanceBusinessKeyLike("%" + title + "%");
                }

                taskPageList = rowsDataQuery.orderByTaskCreateTime().desc().listPage(pageRowStartNo, pageSize);
                totalRowcnt = rowsCountQuery.count();

                for (Task task : taskPageList) {

                    String processId = task.getProcessInstanceId();

                    if (processId == null) {
                        //说明是子任务，没有processid
                        Task parentTask = taskService.createTaskQuery().taskId(task.getParentTaskId()).singleResult();
                        processId = parentTask.getProcessInstanceId();
                    }
                    ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
                    ResponseSituationDto psd = new ResponseSituationDto();
                    psd.setCurrentTaskId(task.getId());
                    psd.setCurrentTaskName(task.getName());
                    psd.setCurrentTaskDefinitionKey(task.getTaskDefinitionKey());
                    psd.setProcessTitle(pi.getName());
                    psd.setProcessId(pi.getId());
                    psd.setProcessDefineName(pi.getProcessDefinitionName());
                    psd.setProcessDefineKey(pi.getProcessDefinitionKey());
                    psd.setStartTime(convertTime(pi.getStartTime()));
                    psd.setStartUsername(pi.getStartUserId());
                    psd.setStartUserChineseName(flowableEhrEmpService.getChineseName(pi.getStartUserId()));
                    psd.setCurrentAssignee(task.getAssignee());
                    psd.setCurrentAssigneeName(flowableEhrEmpService.getChineseName(task.getAssignee()));
                    psd.setSysid(pi.getTenantId());
                    psd.setStatus("0");
                    list.add(psd);

                }

                //   logger.info(list.toString());
            } else if (!StringUtils.isEmpty(startUser) || !StringUtils.isEmpty(involveUser) || !CollectionUtils.isEmpty(processDefineKeyList)) {
                //pi.getProcessDefinitionId();//Product:1:46aa53c6-0ec0-11ec-9532-000c299a9069
//            pi.getProcessDefinitionName();//产品成立流程
//            pi.getProcessDefinitionKey();//Product
//            pi.getProcessDefinitionVersion();//1
                //流程模板中文名为粒度
                //也可以按版本号或者key
                List<HistoricProcessInstance> hpis = new ArrayList<>();
                //根据模板中文名称查询全量包括已经结束的
//                if (!StringUtils.isEmpty(processDefineName)) {
//                    hpis = historyService.createHistoricProcessInstanceQuery().processDefinitionName(processDefineName).orderByProcessInstanceStartTime().desc().list();
//                } else if (!StringUtils.isEmpty(title)) {
//                    hpis = historyService.createHistoricProcessInstanceQuery()
//                            .processInstanceNameLike("%" + title + "%").orderByProcessInstanceStartTime().desc().list();
//                } else

                if (!StringUtils.isEmpty(involveUser)) {

                    String processDefineKeyStr = null;
                    if (CollectionUtils.isEmpty(processDefineKeyList)) {
                        //  processDefineKeyList = null;
                    } else {
                        processDefineKeyStr = String.join(",", processDefineKeyList);
                    }

                    if (StringUtils.isEmpty(title)) {
                        title = null;
                    }
                    if (StringUtils.isEmpty(sysid)) {
                        sysid = null;
                    }
                    String hasEndForInvolve = null;
                    if (!hasAll) {
                        if (hasEnd) {
                            hasEndForInvolve = "1";
                        } else {
                            hasEndForInvolve = "0";
                        }
                    }
                    Page<List<Map<String, String>>> done = flowableCommonService.findUserDone(involveUser, processDefineKeyStr, processDefineKeyList, title, begin, end, sysid, hasEndForInvolve, null, pageable);
                    logger.info(String.valueOf(done.stream().count()));

                    for (Object row : done.getContent()) {
                        Map<String, Object> rowColMap = (Map<String, Object>) row;
                        HistoricProcessInstanceEntityImpl hp = new HistoricProcessInstanceEntityImpl();
                        hp.setName(rowColMap.get("title").toString());

                        String defineName = "";
                        if (rowColMap.get("processDefinitionId").toString().contains(":")) {
                            ProcessDefinition ss = repositoryService.createProcessDefinitionQuery().processDefinitionKey(rowColMap.get("processDefinitionId").toString().split(":")[0]).orderByProcessDefinitionVersion().desc().list().get(0);
                            defineName = ss.getName();
                        } else if (rowColMap.get("businessKey") != null) {
                            ProcessDefinition ss = repositoryService.createProcessDefinitionQuery().processDefinitionKey(rowColMap.get("businessKey").toString().split("\\.")[0]).orderByProcessDefinitionVersion().desc().list().get(0);
                            defineName = ss.getName();
                        }
                        hp.setProcessDefinitionName(defineName);
                        hp.setStartUserId(rowColMap.get("startUserId").toString());
                        hp.setTenantId(rowColMap.get("tenantId").toString());
                        hp.setStartTime((Date) rowColMap.get("startTime"));
                        hp.setProcessInstanceId(rowColMap.get("processInstanceId").toString());
                        hp.setId(rowColMap.get("processInstanceId").toString());

                        hpis.add(hp);
                    }
                    totalRowcnt = done.getTotalElements();
                } else {
                    HistoricProcessInstanceQuery hisquery = historyService.createHistoricProcessInstanceQuery();
                    HistoricProcessInstanceQuery hisqueryCount = historyService.createHistoricProcessInstanceQuery();
                    if (isSysid) {
                        hisquery.processInstanceTenantId(sysid);
                        hisqueryCount.processInstanceTenantId(sysid);
                    }
                    if (StrUtil.isNotEmpty(startUser)) {
                        hisquery.startedBy(startUser);
                        hisqueryCount.startedBy(startUser);
                    }
                    if (!CollectionUtils.isEmpty(processDefineKeyList)) {
                        hisquery.processDefinitionKeyIn(processDefineKeyList);
                        hisqueryCount.processDefinitionKeyIn(processDefineKeyList);
                    }
                    if (StrUtil.isNotEmpty(title)) {
                        hisquery.processInstanceNameLike("%" + title + "%");
                        hisqueryCount.processInstanceNameLike("%" + title + "%");
                    }
                    if (!hasAll) {
                        if (hasEnd) {
                            hisquery.finished();
                            hisqueryCount.finished();
                        } else {
                            hisquery.unfinished();
                            hisqueryCount.unfinished();
                        }
                    }
                    hpis = hisquery.startedBefore(end).startedAfter(begin).orderByProcessInstanceStartTime().desc().listPage(pageRowStartNo, pageSize);
                    totalRowcnt = hisqueryCount.startedBefore(end).startedAfter(begin).count();
                }

                List<Task> tasklist = new ArrayList<>();
                for (HistoricProcessInstance pi : hpis) {
                    ResponseSituationDto psd = new ResponseSituationDto();
                    List<CurrentTaskInfoDto> currentTaskInfoDtoList = new ArrayList<>();
                    psd.setStatus("0");
                    TaskQuery taskQuery = taskService.createTaskQuery().processInstanceId(pi.getId());
                    if (isSysid) {
                        taskQuery.taskTenantId(sysid);
                    }
                    if (!CollectionUtils.isEmpty(processDefineKeyList)) {
                        taskQuery.processDefinitionKeyIn(processDefineKeyList);
                    }
                    tasklist = taskQuery.orderByTaskCreateTime().desc().list();

                    //如果流程没结束，查询到任务节点
                    if (!checkProcessEnd(pi.getId())) {
                        if (tasklist != null && tasklist.size() > 0) {
                            Map<String, List<String>> map = new HashMap<String, List<String>>();
                            Map<String, List<String>> taskidmap = new HashMap<String, List<String>>();

                            StringBuffer sbname = new StringBuffer();
                            StringBuffer sbkey = new StringBuffer();
                            StringBuffer sbid = new StringBuffer();
                            StringBuffer sbassignee = new StringBuffer();
                            for (int i = 0; i < tasklist.size(); i++) {
                                if (i != (tasklist.size() - 1)) {
                                    sbkey.append(tasklist.get(i).getTaskDefinitionKey() + "|");
                                    sbname.append(tasklist.get(i).getName() + "|");
                                    sbassignee.append(tasklist.get(i).getAssignee() + "|");
                                    sbid.append(tasklist.get(i).getId() + "|");

                                    String key = tasklist.get(i).getTaskDefinitionKey() + "|" + tasklist.get(i).getName();
                                    List<String> assigneeList = new ArrayList<>();
                                    List<String> taskIdList = new ArrayList<>();
                                    if (map.get(key) != null) {
                                        assigneeList = map.get(key);
                                    }
                                    assigneeList.add(tasklist.get(i).getAssignee());
                                    map.put(key, assigneeList);

                                    if (taskidmap.get(key) != null) {
                                        taskIdList = taskidmap.get(key);
                                    }
                                    taskIdList.add(tasklist.get(i).getId());
                                    taskidmap.put(key, taskIdList);
                                } else {
                                    sbkey.append(tasklist.get(i).getTaskDefinitionKey());
                                    sbname.append(tasklist.get(i).getName());
                                    sbassignee.append(tasklist.get(i).getAssignee());
                                    sbid.append(tasklist.get(i).getId());

                                    String key = tasklist.get(i).getTaskDefinitionKey() + "|" + tasklist.get(i).getName();
                                    List<String> assigneeList = new ArrayList<>();
                                    List<String> taskIdList = new ArrayList<>();
                                    if (map.get(key) != null) {
                                        assigneeList = map.get(key);
                                    }
                                    assigneeList.add(tasklist.get(i).getAssignee());
                                    map.put(key, assigneeList);

                                    if (taskidmap.get(key) != null) {
                                        taskIdList = taskidmap.get(key);
                                    }
                                    taskIdList.add(tasklist.get(i).getId());
                                    taskidmap.put(key, taskIdList);
                                }


                            }
                            psd.setCurrentTaskDefinitionKey(sbkey.toString());
                            psd.setCurrentTaskName(sbname.toString());
                            psd.setCurrentTaskId(sbid.toString());
                            psd.setCurrentAssignee(sbassignee.toString());
                            psd.setCurrentAssigneeName(flowableEhrEmpService.getChineseNameAll(sbassignee.toString(), "|"));

                            for (Map.Entry<String, List<String>> m : map.entrySet()) {
                                List<String> userid = m.getValue();
                                List<String> username = new ArrayList<>();
                                for (String id : userid) {
                                    username.add(flowableEhrEmpService.getChineseName(id));
                                }

                                String[] defname = m.getKey().split("\\|");
                                CurrentTaskInfoDto currentTaskInfoDto = new CurrentTaskInfoDto();
                                currentTaskInfoDto.setCurrentTaskName(defname[1]);
                                currentTaskInfoDto.setCurrentTaskDefinitionKey(defname[0]);
                                currentTaskInfoDto.setCurrentAssigneeList(m.getValue());
                                currentTaskInfoDto.setCurrentAssigneeNameList(username);
                                currentTaskInfoDto.setCurrentTaskIdList(taskidmap.get(m.getKey()));
                                currentTaskInfoDtoList.add(currentTaskInfoDto);
                            }

                        } else {
                            //流程未结束，且还有任务未完成，说明是其他sysid的流程，跳过
                            //continue;
                        }
                    } else {
                        psd.setStatus("1");
                        List<FlowableDetail> delist = flowableDetailService.findDetailByProcessId(pi.getId());
                        if (delist != null && delist.size() > 0) {
                            String status = delist.get(0).getProcessStatus();
                            //status2为stop手动结束，置状态
                            //status3为delete，不会出现在这个接口
                            if (("2").equals(status)) {
                                psd.setStatus("2");
                            }
                        }
                    }
                    psd.setProcessTitle(pi.getName());
                    psd.setProcessId(pi.getId());
                    psd.setProcessDefineName(pi.getProcessDefinitionName());
                    ProcessInstance p = runtimeService.createProcessInstanceQuery().processInstanceId(pi.getId()).singleResult();
                    if (p == null) {
                        HistoricProcessInstance hp = historyService.createHistoricProcessInstanceQuery().processInstanceId(pi.getId()).singleResult();
                        if (hp != null) {
                            psd.setProcessDefineKey(hp.getProcessDefinitionKey());
                        }
                    } else {
                        psd.setProcessDefineKey(p.getProcessDefinitionKey());
                    }

                    psd.setStartTime(convertTime(pi.getStartTime()));
                    if (pi.getEndTime() != null) {//如果流程结束，则返回流程结束时间
                        psd.setEndTime(convertTime(pi.getEndTime()));
                    }
                    psd.setStartUsername(pi.getStartUserId());
                    psd.setStartUserChineseName(flowableEhrEmpService.getChineseName(pi.getStartUserId()));
                    psd.setSysid(pi.getTenantId());

                    psd.setCurrentTaskInfoDtoList(currentTaskInfoDtoList);
                    list.add(psd);
                }
                //    logger.info(list.toString());
            }

            PageDataResult pageDataResult = new PageDataResult();
            pageDataResult.setList(list);
            pageDataResult.setTotals(totalRowcnt.intValue());
//            Page page = new PageImpl<ProcessSituationDto>(list, pageable, totalRowcnt);
            return FlowableResponse.success(pageDataResult);

        } catch (Exception e) {
            logger.error("flowable流程查询流程实例列表参数错误！", e);
            return FlowableResponse.error("flowable流程查询流程实例列表参数错误! e.getMessage=" + e.getMessage());
        }
    }


    /**
     * 查看流程实例历史明细
     */
    @RequestMapping(method = RequestMethod.POST, value = "/hisDetailList")
    @ApiOperation(value = "查看流程实例历史明细", notes = "查看流程实例历史明细")
    public FlowableResponse<PageDataResult<ResponseDetailDto>> hisDetailList(@RequestParam(value = "pageNum") Integer pageNum,
                                                                             @RequestParam(value = "pageSize") Integer pageSize, @RequestBody ParamHisdetailDto params) {
        try {

            Pageable pageable = PageRequest.of(PageUtil.initPageNo(pageNum) - 1, PageUtil.initPageSize(pageSize));
            //开始行
            Integer pageRowStartNo = ((Long) pageable.getOffset()).intValue();
            Long totalRowcnt = 0L;


            String processId = params.getProcessId();
            if (StringUtils.isEmpty(processId)) {
                logger.error("查看流程实例历史明细失败，processId不能为空");
                return FlowableResponse.error("查看流程实例历史明细失败，processId不能为空");
            }
            String sysid = params.getSysid();

            List<ResponseDetailDto> pddl = new ArrayList<>();

            HistoricProcessInstance pi = historyService.createHistoricProcessInstanceQuery().processInstanceId(processId).singleResult();
            if (pi == null) {
                logger.error("hisdetaillist查询不到该流程！ processId=" + processId);
                return FlowableResponse.success(PageDataResult.empty());
            }


            List<HistoricTaskInstance> list = null;

            if (StringUtils.isEmpty(sysid)) {

                list = historyService
                        .createHistoricTaskInstanceQuery()
                        .processInstanceId(processId).orderByHistoricTaskInstanceStartTime().asc()
                        .listPage(pageRowStartNo, pageSize);
                totalRowcnt = historyService.createHistoricTaskInstanceQuery().processInstanceId(processId).count();
            } else {
                if (!sysid.equals(pi.getTenantId())) {
                    logger.error("hisdetaillist系统名称不匹配！ sysid=" + sysid);
                    return FlowableResponse.error("hisdetaillist系统名称不匹配！ sysid=" + sysid);
                }
                list = historyService
                        .createHistoricTaskInstanceQuery()
                        .processInstanceId(processId).taskTenantId(sysid).orderByHistoricTaskInstanceStartTime().asc()
                        .listPage(pageRowStartNo, pageSize);
                totalRowcnt = historyService.createHistoricTaskInstanceQuery().processInstanceId(processId).taskTenantId(sysid).count();
            }

            if (list != null && list.size() > 0) {
                for (HistoricTaskInstance hti : list) {
                    ResponseDetailDto pdd = new ResponseDetailDto();
                    pdd.setAssignee(hti.getAssignee());
                    pdd.setTaskId(hti.getId());
                    pdd.setTaskName(hti.getName());
                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    String recTime = sdf.format(hti.getCreateTime());
                    pdd.setRecTime(recTime);
                    if (hti.getEndTime() != null) {
                        String opTime = sdf.format(hti.getEndTime());
                        pdd.setOpTime(opTime);
                    }
                    pddl.add(pdd);
                }
                //   logger.info(pddl.toString());
            }

            PageDataResult pageDataResult = new PageDataResult();
            pageDataResult.setCode(0);
            pageDataResult.setTotals(totalRowcnt.intValue());
            pageDataResult.setList(pddl);

            return FlowableResponse.success(pageDataResult);
        } catch (Exception e) {
            logger.error("flowable查看流程实例历史明细错误！", e);
            return FlowableResponse.error("flowable查看流程实例历史明细错误！e.getMessage=" + e.getMessage());
        }
    }

    /**
     * 给用户增加流程的抄送，支持多次抄送
     * * *
     */


    @RequestMapping(method = RequestMethod.POST, value = "/copyProcess")
    @ApiOperation(value = "抄送流程", notes = "抄送流程")
    public FlowableResponse<ResponseMsgDto> copyProcess(@RequestBody ParamCopyDto param) throws UnsupportedEncodingException {
        HistoricProcessInstance pi = historyService.createHistoricProcessInstanceQuery().processInstanceId(param.getProcessId()).singleResult();
        if (pi == null) {
            return FlowableResponse.error("流程不存在");
        }
        if (Strings.isBlank(param.getUsernameDestination())) {
            return FlowableResponse.error("无抄送人");
        }
        flowableCopyService.addCopy(param, pi);
        return FlowableResponse.success(new ResponseMsgDto("抄送成功"));
    }

    @RequestMapping(method = RequestMethod.POST, value = "/getCopyProcessList")
    @ApiOperation(value = "查询抄送流程", notes = "查询抄送流程")
    public FlowableResponse<PageDataResult<FlowableCopyDto>> getCopyProcessList(@RequestParam(value = "pageNum") Integer pageNum,
                                                                                @RequestParam(value = "pageSize") Integer pageSize, @RequestBody ParamGetCopyListDto params) {

        Pageable pageable = PageRequest.of(PageUtil.initPageNo(pageNum) - 1, PageUtil.initPageSize(pageSize));

        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        LocalDateTime beginDate = null;
        LocalDateTime endDate = null;
        try {
            if (!StringUtils.isEmpty(params.getBeginDate())) {
                Date beginDateTmp = sdf.parse(params.getBeginDate());
                Instant instant = beginDateTmp.toInstant();
                ZoneId zoneId = ZoneId.systemDefault();
                beginDate = instant.atZone(zoneId).toLocalDateTime();
            }
            if (!StringUtils.isEmpty(params.getEndDate())) {
                Date endDateTmp = sdf.parse(params.getEndDate());
                Instant instant = endDateTmp.toInstant();
                ZoneId zoneId = ZoneId.systemDefault();
                endDate = instant.atZone(zoneId).toLocalDateTime();
            }
        } catch (Exception e) {
            logger.error("flowable查询抄送流程日期转换异常，请检查！", e);
        }
        Page<FlowableCopyDto> list = flowableCopyService.getCopyProcessList(params.getTitle(), params.getProcessDefinitionKey(), params.getUsernameDestination(), params.getSysid(), params.getStatus(), params.getStartUser(), beginDate, endDate, pageable);

        PageDataResult pageDataResult = new PageDataResult();
        pageDataResult.setCode(0);
        pageDataResult.setTotals((int) list.getTotalElements());
        pageDataResult.setList(list.getContent());

        return FlowableResponse.success(pageDataResult);
    }


    /**
     * 更新抄送状态任务为已读状态，即待阅事件已经被处理
     *
     * @return
     */
    @RequestMapping(method = RequestMethod.POST, value = "/getCopyProcessDetail")
    @ApiOperation(value = "查询抄送流程细节-更新抄送状态任务为已读状态", notes = "查询抄送流程细节-更新抄送状态任务为已读状态")
    public FlowableResponse<ResponseCopyDetailDto> getCopyProcessDetail(@RequestBody ParamCopyDetailDto params) {
        if (StrUtil.isEmpty(params.getProcessId()) || StrUtil.isEmpty(params.getUserId()) || StrUtil.isEmpty(params.getSysid())) {
            logger.info("用户，已阅流程，必要信息为空-{}-{}-{}", params.getUserId(), params.getProcessId(), params.getSysid());
            return FlowableResponse.success(new ResponseCopyDetailDto(new ArrayList<>()));
        }

        flowableCopyService.getCopyProcessDetail(params.getProcessId(), params.getUserId(), params.getSysid());

        List<CopyDetailDto> list = new ArrayList<>();
        List<Task> tasks = taskService.createTaskQuery().processInstanceId(params.getProcessId()).taskTenantId(params.getSysid()).list();
        for (Task ta : tasks) {
            CopyDetailDto detailDto = new CopyDetailDto();
            detailDto.setCurrentTaskName(ta.getName());
            detailDto.setCurrentAssignee(ta.getAssignee());
            detailDto.setCurrentTaskDefinitionKey(ta.getTaskDefinitionKey());
            detailDto.setCurrentTaskId(ta.getId());
            detailDto.setCurrentAssigneeName(flowableEhrEmpService.getChineseName(ta.getAssignee()));
            list.add(detailDto);
        }
        return FlowableResponse.success(new ResponseCopyDetailDto(list));
    }

    @RequestMapping(method = RequestMethod.POST, value = "/getCopyProcessOfUser")
    @ApiOperation(value = "查询用户对某个流程的抄送信息", notes = "查询用户对某个流程的抄送信息")
    public FlowableResponse<ResponseCopyUserDto> getCopyProcessOfUser(@RequestBody ParamCopyUserDto params) {
        List<FlowableCopyDto> copyList = flowableCopyService.getCopyProcessOfUser(params.getProcessId(), params.getUserId(), params.getSysid());
        ResponseCopyUserDto responseCopyUserDto = new ResponseCopyUserDto();
        responseCopyUserDto.setProcessId(params.getProcessId());
        responseCopyUserDto.setUserId(params.getUserId());
        responseCopyUserDto.setSysid(params.getSysid());
        responseCopyUserDto.setCopyList(copyList);
        return FlowableResponse.success(responseCopyUserDto);
    }

    @RequestMapping(method = RequestMethod.POST, value = "/addTaskComment", consumes = "application/json")
    @ApiOperation(value = "增加任务评论", notes = "增加任务评论")
    public FlowableResponse<ResponseMsgDto> addTaskComment(@RequestBody ParamAddTaskCommentDto params) {
        try {
            if (StringUtils.isEmpty(params)) {
                return FlowableResponse.error("增加任务评论参数为空");
            }
            if (StringUtils.isEmpty(params.getTaskId())) {
                return FlowableResponse.error("增加任务评论参数任务id为空");
            }
            if (StringUtils.isEmpty(params.getProcessId())) {
                return FlowableResponse.error("增加任务评论参数流程id为空");
            }
            Authentication.setAuthenticatedUserId(params.getUserId());
            if (!StringUtils.isEmpty(params.getFullMessage())) {
                taskService.addComment(params.getTaskId(), params.getProcessId(), params.getFullMessage());
            } else {
                taskService.addComment(params.getTaskId(), params.getProcessId(), "");
            }
            flowableCommentSupplementService.signTask(params.getTaskId());

            return FlowableResponse.success(new ResponseMsgDto("增加任务评论成功"));
        } catch (Exception e) {
            logger.error("flowable增加任务评论失败！", e);
            return FlowableResponse.error("flowable增加任务评论失败! e.getMessage=" + e.getMessage());
        }
    }


    /**
     * 批准
     * <p>
     * taskId
     * content
     * sysid
     * comment
     */
    @RequestMapping(method = RequestMethod.POST, value = "/doTask", consumes = "application/json")
    @ApiOperation(value = "审批流程", notes = "审批流程")
    public FlowableResponse<ResponseMsgDto> doTask(@RequestBody ParamDoTaskDto params) {
        logger.info("【step】dotask,start");
        String processInstanceId = "";
        try {
            String taskId = params.getTaskId();
            if (StringUtils.isEmpty(taskId)) {
                return FlowableResponse.error("任务流程审批失败，taskId不能为空");
            }
            String content = params.getContent();
            if (StringUtils.isEmpty(content)) {
                return FlowableResponse.error("任务流程审批失败，content不能为空");
            }
//            JSONObject jsoncontent = new JSONObject(content);
//            String title = jsoncontent.getString("title");
//            if (StringUtils.isEmpty(title)) {
//                return FlowableResponse.error("任务流程审批失败，title不能为空");
//            }
            String sysid = params.getSysid();
            if (StringUtils.isEmpty(sysid)) {
                return FlowableResponse.error("任务流程审批失败，sysid不能为空");
            }

            Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
            if (task == null) {
                throw new RuntimeException("任务流程不存在！taskid=null");
            }
            ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(task.getProcessInstanceId()).singleResult();
            processInstanceId = pi.getProcessInstanceId();
            TransactionStatus status = null;

            try {
                // 事务定义
                DefaultTransactionDefinition def = new DefaultTransactionDefinition();
                // 每次都开启一个新事务
                def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
                // 获取事务状态
                status = transactionManager.getTransaction(def);


                //通过审核
                HashMap<String, Object> map = new HashMap<>();
                map.put("sysid", sysid);
                map.put("content", content);

                //查看是否有新的变量传入
                Map<String, Object> existVar = runtimeService.getVariables(pi.getProcessInstanceId());
                //如果有，更新流程变量
                if (params.getTaskAssignee() != null && params.getTaskAssignee().size() > 0) {
                    //  map.put("taskAssignee", params.getTaskAssignee());
                    Map<String, Object> existAssignee = new HashMap<>();
                    if (existVar != null) {
                        if ((Map<String, Object>) existVar.get("taskAssignee") != null) {
                            existAssignee = (Map<String, Object>) existVar.get("taskAssignee");
                        }
                    }
                    for (Map.Entry<String, String> m : params.getTaskAssignee().entrySet()) {
                        existAssignee.put(m.getKey(), m.getValue());
                    }
                    runtimeService.setVariable(pi.getProcessInstanceId(), "taskAssignee", existAssignee);
                }
                if (params.getConditionalVariable() != null && params.getConditionalVariable().size() > 0) {
                    map.put("conditionalVariable", params.getConditionalVariable());
                    Map<String, Object> existConditionalVariable = new HashMap<>();
                    if (existVar != null) {
                        if ((Map<String, Object>) existVar.get("conditionalVariable") != null) {
                            existConditionalVariable = (Map<String, Object>) existVar.get("conditionalVariable");
                        }
                    }
                    for (Map.Entry<String, String> m : params.getConditionalVariable().entrySet()) {
                        existConditionalVariable.put(m.getKey(), m.getValue());
                    }
                    runtimeService.setVariable(pi.getProcessInstanceId(), "conditionalVariable", existConditionalVariable);
                }

                DoTaskCommentDto comment = params.getComment();
                //如果有评论，增加评论
                Authentication.setAuthenticatedUserId(task.getAssignee());
                if (!StringUtils.isEmpty(comment)) {
                    if (!StringUtils.isEmpty(comment.getFullMessage())) {
                        taskService.addComment(taskId, pi.getProcessInstanceId(), comment.getFullMessage());
                    } else {
                        taskService.addComment(taskId, pi.getProcessInstanceId(), "");
                    }

                    //如果有附件，增加附件
                    if (comment.getAppendDto() != null && comment.getAppendDto().size() > 0) {
                        for (AppendDto d : comment.getAppendDto()) {
                            Attachment attachment = taskService.createAttachment("commentAttachment", taskId, pi.getProcessInstanceId(), d.getAnnexName(), task.getTaskDefinitionKey() + ":" + d.getAnnexName(), d.getAnnexUrl());
                            taskService.saveAttachment(attachment);
                        }
                    }
                } else {
                    taskService.addComment(taskId, pi.getProcessInstanceId(), "");
                }
                taskService.complete(taskId, map);

                //入库
                flowableDetailService.addProcessInstanceByTask(task, pi, sysid, content, pi.getName(), "doTask");

                transactionManager.commit(status);
            }
//            catch (FlowableOptimisticLockingException e) {
//                logger.error("flowable-dotask触发并发问题，进行回滚，并重试一次。title=" + title);
//                transactionManager.rollback(status);
//
//                Thread.sleep(2000);
//                try {
//                    // 事务定义
//                    DefaultTransactionDefinition def = new DefaultTransactionDefinition();
//                    // 每次都开启一个新事务
//                    def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
//                    // 获取事务状态
//                    status = transactionManager.getTransaction(def);
//
//                    //通过审核
//                    HashMap<String, Object> map = new HashMap<>();
//                    map.put("sysid", sysid);
//                    map.put("content", content);
//
//                    //查看是否有新的变量传入
//                    Map<String, Object> existVar = runtimeService.getVariables(pi.getProcessInstanceId());
//                    //如果有，更新流程变量
//                    if (params.getTaskAssignee() != null && params.getTaskAssignee().size() > 0) {
//                        //  map.put("taskAssignee", params.getTaskAssignee());
//                        Map<String, Object> existAssignee = new HashMap<>();
//                        if (existVar != null) {
//                            if ((Map<String, Object>) existVar.get("taskAssignee") != null) {
//                                existAssignee = (Map<String, Object>) existVar.get("taskAssignee");
//                            }
//                        }
//                        for (Map.Entry<String, String> m : params.getTaskAssignee().entrySet()) {
//                            existAssignee.put(m.getKey(), m.getValue());
//                        }
//                        runtimeService.setVariable(pi.getProcessInstanceId(), "taskAssignee", existAssignee);
//                    }
//                    if (params.getConditionalVariable() != null && params.getConditionalVariable().size() > 0) {
//                        map.put("conditionalVariable", params.getConditionalVariable());
//                        Map<String, Object> existConditionalVariable = new HashMap<>();
//                        if (existVar != null) {
//                            if ((Map<String, Object>) existVar.get("conditionalVariable") != null) {
//                                existConditionalVariable = (Map<String, Object>) existVar.get("conditionalVariable");
//                            }
//                        }
//                        for (Map.Entry<String, String> m : params.getConditionalVariable().entrySet()) {
//                            existConditionalVariable.put(m.getKey(), m.getValue());
//                        }
//                        runtimeService.setVariable(pi.getProcessInstanceId(), "conditionalVariable", existConditionalVariable);
//                    }
//
//                    DoTaskCommentDto comment = params.getComment();
//                    //如果有评论，增加评论
//                    if (!StringUtils.isEmpty(comment)) {
//                        Authentication.setAuthenticatedUserId(task.getAssignee());
//                        if (!StringUtils.isEmpty(comment.getFullMessage())) {
//                            taskService.addComment(taskId, pi.getProcessInstanceId(), comment.getFullMessage());
//                        } else {
//                            taskService.addComment(taskId, pi.getProcessInstanceId(), "");
//                        }
//
//                        //如果有附件，增加附件
//                        if (comment.getAppendDto() != null && comment.getAppendDto().size() > 0) {
//                            for (AppendDto d : comment.getAppendDto()) {
//                                Attachment attachment = taskService.createAttachment("commentAttachment", taskId, pi.getProcessInstanceId(), d.getAnnexName(), task.getTaskDefinitionKey() + ":" + d.getAnnexName(), d.getAnnexUrl());
//                                taskService.saveAttachment(attachment);
//                            }
//                        }
//                    } else {
//                        taskService.addComment(taskId, pi.getProcessInstanceId(), "");
//                    }
//                    taskService.complete(taskId, map);
//
//                    //入库
//                    flowableDetailService.addProcessInstanceByTask(task, pi, sysid, content, title, "doTask");
//
//                    transactionManager.commit(status);
//                } catch (Exception e1) {
//                    String errMsg = "flowable-dotask触发并发问题，重试一次出现异常，抛出结束。";
//                    logger.error(errMsg, e1);
//                    transactionManager.rollback(status);
//                    throw new Exception(errMsg);
//                }
//            }
            catch (Exception e) {
                logger.error("任务流程审批失败，请检查！taskid=" + taskId + ",processid=" + pi.getId(), e);
                transactionManager.rollback(status);
                return FlowableResponse.error("任务流程审批失败", "任务流程审批失败，请检查！taskid=" + taskId + ",processid=" + pi.getId() + ", e.getMessage=" + e.getMessage());
            }
            logger.info("进入task监听器,流程备注补充信息3:sign");
            ResponseMsgDto respMsg = new ResponseMsgDto("任务流程审批成功");
            respMsg.setProcessEndFlag(checkProcessEnd(pi.getProcessInstanceId()));
            logger.info("【step】dotask,end");
            return FlowableResponse.success(respMsg);
        } catch (Exception e) {
            logger.error("flowable任务流程审批失败！", e);
            return FlowableResponse.error("flowable任务流程审批失败! e.getMessage=" + e.getMessage());
        } finally {
            logger.info("【step】dotask,end,finally");
            sender.sendMessage(processInstanceId);
        }
    }

    @RequestMapping(method = RequestMethod.POST, value = "/backToStart")
    @ApiOperation(value = "跳回起始接口", notes = "跳回起始接口")
    public FlowableResponse<ResponseMsgDto> backToStart(@RequestBody ParamBackToStartDto params) {
        String processid = null;
        String sysid = null;
        String comment = null;
        String sourceRef = null;
        String taskid = null;
        List<String> sourceList = new ArrayList<>();
        List<String> remindUserList = new ArrayList<>();
        List<String> remindTaskList = new ArrayList<>();
        try {
            comment = params.getComment();
            processid = params.getProcessId();
            if (StringUtils.isEmpty(processid)) {
                return FlowableResponse.error("跳回起始失败，processid不能为空");
            }
            sysid = params.getSysid();
            if (StringUtils.isEmpty(sysid)) {
                return FlowableResponse.error("跳回起始失败，sysid不能为空");
            }
            if (!StringUtils.isEmpty(params.getTaskId())) {
                taskid = params.getTaskId();
            }
        } catch (Exception e) {
            return FlowableResponse.error("跳回起始失败，参数获取异常！ message=" + e.getMessage());
        }

        try {
            ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processid).singleResult();
            sourceRef = params.getStartActivityId();
            if (StringUtils.isEmpty(sourceRef)) {
                String define = pi.getProcessDefinitionKey();
                sourceRef = FlowableConstant.startTaskMap.get(define);
                if (StringUtils.isEmpty(sourceRef)) {
                    sourceRef = "beginTask";
                }
            }
            sourceList.add(sourceRef);
            //添加comment
            if (StringUtils.isEmpty(comment)) {
                comment = "撤回至发起节点";
            }
            if (StringUtils.isEmpty(params.getUserId())) {
                Authentication.setAuthenticatedUserId(pi.getStartUserId());
            } else {
                Authentication.setAuthenticatedUserId(params.getUserId());
            }
            taskService.addComment(taskid, processid, FlowableConstant.BACK_TAG + comment);
            flowableCommentSupplementService.signTask(taskid);

            List<String> currentExecutionIds = new ArrayList<>();
            List<Execution> executions = runtimeService.createExecutionQuery().parentId(processid).list();
            for (Execution execution : executions) {
                logger.info("现在进行的节点：" + execution.getActivityId());
                ExecutionEntity entity = (ExecutionEntity) execution;
                currentExecutionIds.add(execution.getId());
            }

            List<Task> list = taskService.createTaskQuery().processInstanceId(processid).active().list();
            List<String> targetList = list.stream().map(Task::getTaskDefinitionKey).distinct().collect(Collectors.toList());
            Set<String> userSet = new HashSet<>();
            Set<String> taskSet = new HashSet<>();
            processService.callBackRemindActivitors(processid, sourceList, targetList, userSet, taskSet);
            remindUserList.addAll(userSet);
            remindTaskList.addAll(taskSet);
            runtimeService.createChangeActivityStateBuilder().processInstanceId(processid)
                    .moveExecutionsToSingleActivityId(currentExecutionIds, sourceRef).changeState();
        } catch (Exception e) {
            logger.error("跳回起始失败，请检查！ processid={}", processid, e);
            return FlowableResponse.error("跳回起始失败", "回退失败，请检查！,processid=" + processid + ",e.getMessage=" + e.getMessage());
        }
        return FlowableResponse.success(new ResponseMsgDto("跳回起始成功", remindUserList, remindTaskList));
    }

    /**
     * 回退驳回
     * <p>
     * taskId
     * content
     * sysid
     * comment
     */
    @RequestMapping(method = RequestMethod.POST, value = "/rollback")
    @ApiOperation(value = "回退接口", notes = "回退接口")
    public FlowableResponse<ResponseMsgDto> rollback(@RequestBody ParamRollbackDto params) {
        String processid = null;
        String taskId = null;
        String content = null;
        String title = null;
        String sysid = null;
        String comment = null;
        try {
            comment = params.getComment();

            taskId = params.getTaskId();
            if (StringUtils.isEmpty(taskId)) {
                return FlowableResponse.error("任务流程回退失败，taskId不能为空");
            }
            content = params.getContent();
            if (StringUtils.isEmpty(content)) {
                return FlowableResponse.error("任务流程回退失败，content不能为空");
            }
//            JSONObject jsoncontent = new JSONObject(content);
//            title = jsoncontent.getString("title");
//            if (StringUtils.isEmpty(title)) {
//                return FlowableResponse.error("任务流程回退失败，title不能为空");
//            }
            sysid = params.getSysid();
            if (StringUtils.isEmpty(sysid)) {
                return FlowableResponse.error("任务流程回退失败，sysid不能为空");
            }
        } catch (Exception e) {
            return FlowableResponse.error("任务流程回退失败，参数获取异常！ message=" + e.getMessage());
        }

        try {
            Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
            processid = task.getProcessInstanceId();
            ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processid).singleResult();
            ExecutionEntity ee = (ExecutionEntity) processEngine.getRuntimeService().createExecutionQuery()
                    .executionId(task.getExecutionId()).singleResult();
            // 当前审批节点
            String currentActivityId = ee.getActivityId();//acitivtyId，即流程节点ID

            //  List<Task> list1 = taskService.createTaskQuery().processInstanceId(task.getProcessInstanceId()).list();
//                taskService.addComment(currentTask.getId(), execution.getProcessInstanceId(), body.get("msg").toString());

            BpmnModel bpmnModel = repositoryService.getBpmnModel(ee.getProcessDefinitionId());
            FlowNode flowNode = (FlowNode) bpmnModel.getFlowElement(currentActivityId);

            FlowElement source = bpmnModel.getFlowElement(currentActivityId);

            SequenceFlow sequenceFlow = flowNode.getIncomingFlows().get(0);
            // 获取上一个节点的activityId，目前没有考虑上一个节点时多个的情况。
            String sourceRef = sequenceFlow.getSourceRef();
            //取得income的上一个节点
            FlowElement presource = sequenceFlow.getSourceFlowElement();


            boolean ifParallelGateway = false;
            boolean rootgateway = false;
            if (presource instanceof org.flowable.bpmn.model.Task) {
                logger.info("task");
            } else if (presource instanceof Gateway) {
                //如果是网关，再往前退一个节点
                if (presource instanceof ParallelGateway) {
                    logger.info("ParallelGateway");
                    flowNode = (FlowNode) presource;
                    ifParallelGateway = true;
                    if (flowNode.getOutgoingFlows().size() > 1) {
                        rootgateway = true;
                    }
                }
                if (presource instanceof ExclusiveGateway) {
                    logger.info("ExclusiveGateway");
                    flowNode = (FlowNode) presource;
                }
                logger.info("Gateway");
            } else if (presource instanceof SubProcess) {
                logger.info("SubProcess");
            } else if (presource instanceof StartEvent) {
                logger.info("StartEvent");
            } else if (presource instanceof EndEvent) {
                logger.info("EndEvent");
            }

            if (StringUtils.isEmpty(params.getUserId())) {
                Authentication.setAuthenticatedUserId(task.getAssignee());
            } else {
                Authentication.setAuthenticatedUserId(params.getUserId());
            }
            //添加comment
            if (StrUtil.isNotBlank(comment)) {
                taskService.addComment(taskId, processid, FlowableConstant.BACK_TAG + comment);
                flowableCommentSupplementService.signTask(taskId);
            } else {
                taskService.addComment(taskId, processid, FlowableConstant.BACK_TAG);
                flowableCommentSupplementService.signTask(taskId);
            }

            //如果上一节点是并行网关
            if (ifParallelGateway) {
                if (rootgateway) {
                    //类似于<
                    //如果上一节点是并行网关，且网关的出口有多个，则退回网关前的节点，清理网关后的节点
                    String exe = null;
                    String tsk = null;
                    //flowNode 是网关本身
                    for (SequenceFlow sf : flowNode.getIncomingFlows()) {
                        List<HistoricTaskInstance> hyi = historyService.createHistoricTaskInstanceQuery().processInstanceId(pi.getProcessInstanceId()).taskDefinitionKey(sf.getSourceRef()).orderByHistoricTaskInstanceEndTime().desc().list();
                        for (HistoricTaskInstance i : hyi) {
                            if (i.getEndTime() != null) {
                                sourceRef = sf.getSourceRef();
                                break;
                            }
                        }
                    }
                    List<String> currentExecutionIds = new ArrayList<>();
                    List<Execution> executions = runtimeService.createExecutionQuery().parentId(task.getProcessInstanceId()).list();

                    for (Execution execution : executions) {
                        logger.info("并行网关节点数：" + execution.getActivityId());
                        ExecutionEntity entity = (ExecutionEntity) execution;
                        if (isBelongtoSource(execution.getId(), sourceRef, task.getProcessDefinitionId())) {
                            currentExecutionIds.add(execution.getId());
                        }
                    }

                    // 流程回退到上一个节点，审批人继续审批
                    runtimeService.createChangeActivityStateBuilder().processInstanceId(task.getProcessInstanceId())
                            .moveExecutionsToSingleActivityId(currentExecutionIds, sourceRef).changeState();
                } else {
                    //类似于>
                    //如果上一节点是并行网关，则退回所有已完成的网关前的节点
                    List<String> currentTaskKeys = new ArrayList<>();
                    for (SequenceFlow seqFlow : flowNode.getIncomingFlows()) {
                        List<HistoricTaskInstance> hyi = historyService.createHistoricTaskInstanceQuery().processInstanceId(pi.getProcessInstanceId())
                                .taskDefinitionKey(seqFlow.getSourceRef()).orderByHistoricTaskInstanceEndTime().desc().list();
                        for (HistoricTaskInstance i : hyi) {
                            if (i.getEndTime() != null) {
                                //增加判断，是否前后节点的确触发执行
                                boolean canTriggerFlag = this.canSequenceFlowRun(seqFlow, ee);
                                logger.info("判断前后节点是否的确能够触发：{}-{}，triggerFlag={}", i.getTaskDefinitionKey(), task.getTaskDefinitionKey(), canTriggerFlag);
                                if (canTriggerFlag) {
                                    currentTaskKeys.add(i.getTaskDefinitionKey());
                                }
                            }
                        }
                    }
                    logger.info("流程回退到上一个节点，退回列表：", currentTaskKeys);
                    // 流程回退到上一个节点，审批人继续审批
                    runtimeService.createChangeActivityStateBuilder().processInstanceId(task.getProcessInstanceId())
                            .moveSingleActivityIdToActivityIds(currentActivityId, currentTaskKeys).changeState();
                }
            } else {
                //常规串行
                boolean moreIncomingFlows = false;
                if (flowNode.getIncomingFlows().size() > 1) {
                    moreIncomingFlows = true;
                }
                if (moreIncomingFlows) {
                    //常规串行 多入口 >
                    List<String> currentTaskKeys = new ArrayList<>();
                    for (SequenceFlow seqFlow : flowNode.getIncomingFlows()) {
                        List<HistoricTaskInstance> hyi = historyService.createHistoricTaskInstanceQuery().processInstanceId(pi.getProcessInstanceId()).taskDefinitionKey(seqFlow.getSourceRef()).orderByHistoricTaskInstanceEndTime().desc().list();
                        for (HistoricTaskInstance i : hyi) {
                            //增加判断，是否前后节点的确触发执行
                            boolean canTriggerFlag = this.canSequenceFlowRun(seqFlow, ee);
                            logger.info("判断前后节点是否的确能够触发：{}-{}，triggerFlag={}", i.getTaskDefinitionKey(), task.getTaskDefinitionKey(), canTriggerFlag);
                            if (canTriggerFlag) {
                                currentTaskKeys.add(i.getTaskDefinitionKey());
                            }
                        }
                    }
                    // 流程回退到上多个节点，审批人继续审批
                    runtimeService.createChangeActivityStateBuilder().processInstanceId(task.getProcessInstanceId())
                            .moveSingleActivityIdToActivityIds(currentActivityId, currentTaskKeys).changeState();
                } else {//前序节点只有一个
                    FlowNode preTask = (FlowNode) presource;
                    //A<B1/B2这种场景，B1或者B2退回到A节点时，需要检查A节点是否之前存在，by zzp,20221103
                    List<HistoricTaskInstance> sourceRefTaskList = historyService.createHistoricTaskInstanceQuery().processInstanceId(pi.getProcessInstanceId()).taskDefinitionKey(sourceRef).orderByHistoricTaskInstanceEndTime().desc().list();
                    if (CollectionUtils.isEmpty(sourceRefTaskList)) {
                        throw new RuntimeException("退回到上一个节点时，无有效的直接前序节点可以退回！！！");
                    }
                    //End of 判断前序节点之前存在过


                    if (preTask.getOutgoingFlows().size() > 1) {
                        //非常规串行，分叉的多出口 <
                        List<String> currentExecutionIds = new ArrayList<>();
                        List<Execution> executions = runtimeService.createExecutionQuery().parentId(task.getProcessInstanceId()).list();
                        for (Execution execution : executions) {
                            logger.info("并行网关节点数：" + execution.getActivityId());
                            ExecutionEntity entity = (ExecutionEntity) execution;
                            if (isBelongtoSource(execution.getId(), sourceRef, task.getProcessDefinitionId())) {
                                currentExecutionIds.add(execution.getId());
                            }
                        }
                        runtimeService.createChangeActivityStateBuilder().processInstanceId(task.getProcessInstanceId())
                                .moveExecutionsToSingleActivityId(currentExecutionIds, sourceRef).changeState();
                    } else {
                        //常规串行，线性
                        for (SequenceFlow sf : flowNode.getIncomingFlows()) {
                            List<HistoricTaskInstance> hyi = historyService.createHistoricTaskInstanceQuery().processInstanceId(pi.getProcessInstanceId()).taskDefinitionKey(sf.getSourceRef()).orderByHistoricTaskInstanceEndTime().desc().list();
                            for (HistoricTaskInstance i : hyi) {
                                if (i.getEndTime() != null) {
                                    sourceRef = sf.getSourceRef();
                                    break;
                                }
                            }
                        }
                        // 流程回退到上一个节点，审批人继续审批
                        runtimeService.createChangeActivityStateBuilder().processInstanceId(task.getProcessInstanceId())
                                .moveActivityIdTo(currentActivityId, sourceRef).changeState();
                    }
                }
            }
            //入库
            flowableDetailService.addProcessInstanceByTask(task, pi, sysid, content, pi.getName(), "rollback");
        } catch (Exception e) {
            logger.error("任务流程回退失败，请检查！taskid=" + taskId + ",processid=" + processid, e);
            return FlowableResponse.error("任务流程回退失败", "回退失败，请检查！taskid=" + taskId + ",processid=" + processid + ",e.getMessage=" + e.getMessage());
        }
        return FlowableResponse.success(new ResponseMsgDto("任务流程回退成功"));
    }

    /**
     * 检查某个节点是否会实际触发后续节点
     * 解决问题：有些节点前后有连线，但是附条件执行，这个函数用于判断是否真实执行，关键在ConditionUtil.hasTrueCondition(sequenceFlow, execution)
     * 用途：A1/A2等多个分支到达>B节点，此场景B退回时，需要判断A1-B或者A2-B这个连线是否成立
     *
     * @author zzp
     * *
     * * *
     */
    public boolean canSequenceFlowRun(SequenceFlow sequenceFlow, Execution execution) {
        if (sequenceFlow == null || execution == null) {
            return true;
        }

        ManagementService managementService = processEngine.getManagementService();
        Boolean canTriggerFlag = managementService.executeCommand(new Command<Boolean>() {
            @Override
            public Boolean execute(CommandContext commandContext) {
                boolean conditionFlag = ConditionUtil.hasTrueCondition(sequenceFlow, (DelegateExecution) execution);
                logger.info("流程连线：{}，在实例中是否会运行={}", sequenceFlow, conditionFlag);
                return conditionFlag;
            }
        });

        return canTriggerFlag;
    }

    /**
     * 待办
     * 查询当前节点的父节点表单内容
     */
    @ResponseBody
    @RequestMapping(value = "queryParentFormData")
    public String queryParentFormData(String taskId) {
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        List<HistoricTaskInstance> list = historyService
                .createHistoricTaskInstanceQuery()
                .processInstanceId(task.getProcessInstanceId()).orderByHistoricTaskInstanceEndTime().desc()
                .list();

        //查找当前流程最新已处理的节点
        if (list != null && list.size() > 0) {
            String taskDkey = list.get(0).getTaskDefinitionKey();
            for (HistoricTaskInstance h : list) {
                if (h.getEndTime() != null) {
                    String content = flowableDetailService.queryFormData(h.getId());
                    if (content != null && !content.equals("") && h.getTaskDefinitionKey().equals(taskDkey)) {
                        return content;
                    }
                }
            }
        }
        if (list != null && list.size() > 0) {
            return flowableDetailService.queryStartFormData(task.getProcessInstanceId());
        }
        throw new RuntimeException("上一个节点不存在");
    }

    /**
     * 入口：发起的流程 已办的流程 办结的流程
     * 查询当前流程最新节点的父节点表单内容
     */
    @RequestMapping(value = "queryLatestFormData")
    public String queryLatestFormData(@RequestParam("processId") String processId) {
        return flowableDetailService.queryLatestFormData(processId);
    }

    /**
     * 中止流程
     */
    @RequestMapping(method = RequestMethod.GET, value = "/stop")
    @ApiOperation(value = "终止流程", notes = "终止流程")
    public FlowableResponse<ResponseMsgDto> stopProcessInstanceById(@RequestParam("processId") String processId, @RequestParam(required = false, value = "operator") String operator) {
        try {
            if (StringUtils.isEmpty(processId)) {
                return FlowableResponse.error("任务流程终止失败，processId不能为空");
            }
        } catch (Exception e) {
            return FlowableResponse.error("任务流程终止失败，参数获取异常！ message=" + e.getMessage());
        }
        try {
            ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
            if (processInstance != null) {
                //1、获取终止节点
                List<EndEvent> endNodes = findEndFlowElement(processInstance.getProcessDefinitionId());
                String endId = endNodes.get(0).getId();
                //2、执行终止
                List<Execution> executions = runtimeService.createExecutionQuery().parentId(processId).list();
                List<String> executionIds = new ArrayList<>();
                executions.forEach(execution -> executionIds.add(execution.getId()));
                runtimeService.createChangeActivityStateBuilder().moveExecutionsToSingleActivityId(executionIds, endId).changeState();
                logger.info("终止processInstanceId:{}成功", processId);
                if (StrUtil.isNotBlank(operator)) {
                    FlowableCommentSupplement fcs = new FlowableCommentSupplement();
                    fcs.setTaskId(UUID.randomUUID().toString());
                    fcs.setProcessId(processId);
                    fcs.setTaskName("强制终止");
                    fcs.setTaskAssignee(operator);
                    fcs.setComment("用户:" + flowableEhrEmpService.getChineseName(operator) + ",强制结束当前流程!");
                    fcs.setTaskHandleStatus(FlowableConstant.FLOWABLE_TASK_HANDLE_STATUS_SIGN);
                    logger.info("终止流程,流程备注补充信息:{}", fcs);
                    flowableCommentSupplementService.save(fcs);
                }
                List<FlowableDetail> list = flowableDetailService.findDetailByProcessId(processId);
                if (list != null && list.size() > 0) {
                    flowableDetailService.batchUpdateStatus(list, "2");
                }
                logger.info("更新detail表成功");
            } else {
                logger.info("不存在运行的流程实例processInstanceId:{},请确认!", processId);
            }
            return FlowableResponse.success(new ResponseMsgDto("终止成功"));
        } catch (Exception e) {
            logger.error("终止processInstanceId:{}失败，processId=" + processId, e);
            return FlowableResponse.error("终止processInstanceId:{}失败，processId=" + processId + ",e.getMessage=" + e.getMessage());
        }

    }

    public List findEndFlowElement(String processDefId) {
        Process mainProcess = repositoryService.getBpmnModel(processDefId).getMainProcess();
        Collection<FlowElement> list = mainProcess.getFlowElements();
        if (CollectionUtils.isEmpty(list)) {
            return Collections.EMPTY_LIST;
        }
        return list.stream().filter(f -> f instanceof EndEvent).collect(Collectors.toList());
    }

    /**
     * 查看流程实例是否结束
     * true 结束
     */
    @RequestMapping(method = RequestMethod.GET, value = "checkProcessEnd")
    @ApiOperation(value = "查看流程实例是否结束", notes = "查看流程实例是否结束")
    public boolean checkProcessEnd(@RequestParam("processId") String processId) {
        return processService.checkProcessEnd(processId);
    }

    /**
     * 获取所有task信息
     */
    @RequestMapping(method = RequestMethod.GET, value = "getProcessDefinitionInfo")
    public FlowableResponse<ResponseProcessDefinitionDto> getProcessDefinitionInfo(@RequestParam String
                                                                                           processDefinitionKey, @RequestParam(required = false) Integer processDefinitionVersion) {
        //Product:74:c6acd4dc-107b-11ec-b222-000c299a9069  //159
        ResponseProcessDefinitionDto dto = new ResponseProcessDefinitionDto();
        dto.setProcessDefinitionKey(processDefinitionKey);
        //获取流程发布Id信息
        String definitionId = "";
        List<ProcessDefinition> def = null;
        if (processDefinitionVersion == null || processDefinitionVersion == 0 ) {
            def = repositoryService.createProcessDefinitionQuery().processDefinitionKey(processDefinitionKey).orderByProcessDefinitionVersion().desc().list();
        } else {
            def = repositoryService.createProcessDefinitionQuery().processDefinitionKey(processDefinitionKey).processDefinitionVersion(processDefinitionVersion).list();
        }
        if (def == null || def.size() == 0) {
            return FlowableResponse.error("获取流程信息失败，查不到对应流程定义。 key=" + processDefinitionKey);
        }
        definitionId = def.get(0).getId();
        dto.setProcessDefinitionId(def.get(0).getId());
        dto.setProcessDefinitionVersion(def.get(0).getVersion());

        List<TaskDefinitionDto> taskList = new ArrayList<>();
        //获取所有节点信息
        List<Process> processes = repositoryService.getBpmnModel(definitionId).getProcesses();
        StringBuffer sb = new StringBuffer();
        for (Process process : processes) {
            Collection<FlowElement> flowElements = process.getFlowElements();
            if (CollectionUtils.isNotEmpty(flowElements)) {
                for (FlowElement flowElement : flowElements) {
                    if (flowElement instanceof UserTask) {
                        TaskDefinitionDto td = new TaskDefinitionDto();
                        UserTask task = (UserTask) flowElement;
                        td.setTaskDefinitionKey(task.getId());
                        td.setTaskName(task.getName());
                        taskList.add(td);
                    }
                }
            }
        }
        dto.setTaskList(taskList);
        return FlowableResponse.success(dto);
    }


    /**
     * 获取该task相关信息
     */
    @RequestMapping(method = RequestMethod.GET, value = "getTaskInfo")
    @ApiOperation(value = "获取该task相关信息", notes = "获取该task相关信息")
    public FlowableResponse<ResponseSituationDto> getTaskInfo(@RequestParam("taskId") String taskId, @RequestParam("sysid") String sysid) {

        ResponseSituationDto psd;
        try {
            psd = processService.getTaskInfo(taskId, sysid);
            try {
                List<FlowableCommentSupplement> fcsList = flowableCommentSupplementService.findByTaskId(psd.getCurrentTaskId());
                if (CollUtil.isNotEmpty(fcsList)) {
                    fcsList.forEach(fcs -> fcs.setTaskHandleStatus(FlowableConstant.FLOWABLE_TASK_HANDLE_STATUS_READ));
                    flowableCommentSupplementService.saveAll(fcsList);
                }
            } catch (Exception e) {
                logger.error("进入processCreated监听器异常！", e);
            }
        } catch (Exception e) {
            logger.error("获取该task相关信息报错,taskId=" + taskId, e);
            return FlowableResponse.error("获取该task相关信息报错,taskId=" + taskId);
        }
        return FlowableResponse.success(psd);
    }

    /**
     * 生成流程图 正在用
     *
     * @param processId 任务ID
     */
    @RequestMapping(method = RequestMethod.GET, value = "/processDiagram")
    @ResponseBody
    @ApiOperation(value = "生成流程图", notes = "生成流程图")
    public void genProcessDiagram(HttpServletResponse httpServletResponse, String processId) throws Exception {
        ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
        TransactionSynchronizationManager aa;

        //2.获取所有的历史轨迹对象
        List<HistoricActivityInstance> list = historyService.createHistoricActivityInstanceQuery()
                .processInstanceId(processId).list();
        Map<String, HistoricActivityInstance> hisActivityMap = new HashMap<>();
        list.forEach(historicActivityInstance -> {
            if (!hisActivityMap.containsKey(historicActivityInstance.getActivityId())) {
                hisActivityMap.put(historicActivityInstance.getActivityId(), historicActivityInstance);
            }
        });
        String processDefinitionId = null;
        List<String> activityIds = new ArrayList<>();
        List<String> flows = new ArrayList<>();
        //流程走完的不显示图
        if (pi == null) {
            //3.2. 已经结束的流程实例
            HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(processId).singleResult();
            processDefinitionId = historicProcessInstance.getProcessDefinitionId();
            activityIds = new ArrayList<>();
            List<EndEvent> endEvents = findEndFlowElement(processDefinitionId);
            List<String> finalActiveActivityIds = activityIds;
            endEvents.forEach(endEvent -> {
                if (hisActivityMap.containsKey(endEvent.getId())) {
                    finalActiveActivityIds.add(endEvent.getId());
                }
            });
        } else {
            //Task task = taskService.createTaskQuery().processInstanceId(pi.getId()).singleResult();
            //List<Task> task = taskService.createTaskQuery().processInstanceId(pi.getId()).list();
            //使用流程实例ID，查询正在执行的执行对象表，返回流程实例对象
            //String InstanceId = task.get(0).getProcessInstanceId();

            processDefinitionId = pi.getProcessDefinitionId();
            List<Execution> executions = runtimeService
                    .createExecutionQuery()
                    .processInstanceId(processId)
                    .list();

            //得到正在执行的Activity的Id
            // List<String> activityIds = new ArrayList<>();
            //List<String> flows = new ArrayList<>();
            for (Execution exe : executions) {
                List<String> ids = runtimeService.getActiveActivityIds(exe.getId());
                activityIds.addAll(ids);
            }
        }


        //获取流程图
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
        ProcessEngineConfiguration engconf = processEngine.getProcessEngineConfiguration();
        ProcessDiagramGenerator diagramGenerator = engconf.getProcessDiagramGenerator();
        InputStream in = diagramGenerator.generateDiagram(bpmnModel, "png", activityIds,
                flows, engconf.getActivityFontName(), engconf.getLabelFontName(), engconf.getAnnotationFontName(), engconf.getClassLoader(), 1.0, false);

        OutputStream out = null;
        byte[] buf = new byte[1024];
        int legth = 0;
        try {
            out = httpServletResponse.getOutputStream();
            while ((legth = in.read(buf)) != -1) {
                out.write(buf, 0, legth);
            }
        } finally {
            if (in != null) {
                in.close();
            }
            if (out != null) {
                out.close();
            }
        }
    }


    /**
     * 生成流程图 正在用 接口形式
     *
     * @param processId 任务ID
     */
    @RequestMapping(method = RequestMethod.GET, value = "/processDiagramStream")
    @ApiOperation(value = "生成流程图", notes = "生成流程图")
    public ResponseEntity<byte[]> processDiagramStream(HttpServletResponse httpServletResponse, String processId) throws
            Exception {
        ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();

        //2.获取所有的历史轨迹对象
        List<HistoricActivityInstance> list = historyService.createHistoricActivityInstanceQuery()
                .processInstanceId(processId).list();
        Map<String, HistoricActivityInstance> hisActivityMap = new HashMap<>();
        list.forEach(historicActivityInstance -> {
            if (!hisActivityMap.containsKey(historicActivityInstance.getActivityId())) {
                hisActivityMap.put(historicActivityInstance.getActivityId(), historicActivityInstance);
            }
        });
        String processDefinitionId = null;
        List<String> activityIds = new ArrayList<>();
        List<String> flows = new ArrayList<>();
        //流程走完的不显示图
        if (pi == null) {
            //3.2. 已经结束的流程实例
            HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(processId).singleResult();
            processDefinitionId = historicProcessInstance.getProcessDefinitionId();
            activityIds = new ArrayList<>();
            List<EndEvent> endEvents = findEndFlowElement(processDefinitionId);
            List<String> finalActiveActivityIds = activityIds;
            endEvents.forEach(endEvent -> {
                if (hisActivityMap.containsKey(endEvent.getId())) {
                    finalActiveActivityIds.add(endEvent.getId());
                }
            });
        } else {
            //Task task = taskService.createTaskQuery().processInstanceId(pi.getId()).singleResult();
            //List<Task> task = taskService.createTaskQuery().processInstanceId(pi.getId()).list();
            //使用流程实例ID，查询正在执行的执行对象表，返回流程实例对象
            //String InstanceId = task.get(0).getProcessInstanceId();

            processDefinitionId = pi.getProcessDefinitionId();
            List<Execution> executions = runtimeService
                    .createExecutionQuery()
                    .processInstanceId(processId)
                    .list();

            //得到正在执行的Activity的Id
            // List<String> activityIds = new ArrayList<>();
            //List<String> flows = new ArrayList<>();
            for (Execution exe : executions) {
                List<String> ids = runtimeService.getActiveActivityIds(exe.getId());
                activityIds.addAll(ids);
            }
        }


        //获取流程图
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
        ProcessEngineConfiguration engconf = processEngine.getProcessEngineConfiguration();
        ProcessDiagramGenerator diagramGenerator = engconf.getProcessDiagramGenerator();
        InputStream in = diagramGenerator.generateDiagram(bpmnModel, "png", activityIds,
                flows, engconf.getActivityFontName(), engconf.getLabelFontName(), engconf.getAnnotationFontName(), engconf.getClassLoader(), 1.0, false);
//        byte[] buf = in.readAllBytes();
        OutputStream out = null;
        byte[] buf = new byte[in.available()];
//        int legth = 0;
//        try {
//            out = httpServletResponse.getOutputStream();
//            while ((legth = in.read(buf)) != -1) {
//                out.write(buf, 0, legth);
//            }
//        } finally {
//            if (in != null) {
//                in.close();
//            }
//            if (out != null) {
//                out.close();
//            }
//        }
        BufferedInputStream bin = new BufferedInputStream(in);
        bin.read(buf);
        HttpHeaders headers = new HttpHeaders();
        headers.add("Content-Disposition", "attachment;filename=流程图");
        return new ResponseEntity<byte[]>(buf, headers, HttpStatus.OK);
    }


    private boolean isBelongtoSource(String currentExecuteId, String sourceActivityId, String processDefinitionId) {
        ExecutionEntity currentExecute = (ExecutionEntity) processEngine.getRuntimeService().createExecutionQuery()
                .executionId(currentExecuteId).singleResult();
        // 当前节点
        String crruentActivityId = currentExecute.getActivityId();
        BpmnModel bpmnModel = processEngine.getRepositoryService().getBpmnModel(processDefinitionId);
        FlowNode flowNode = (FlowNode) bpmnModel.getFlowElement(crruentActivityId);
        // 输入连线
        List<SequenceFlow> inFlows = flowNode.getIncomingFlows();

        while (flowNode.getIncomingFlows() != null) {
            inFlows = flowNode.getIncomingFlows();
//            if (inFlows.size() > 1) {
//                return false;
//            }
            FlowElement sourceFlowElement = inFlows.get(0).getSourceFlowElement();
            // FlowElement targetFlow = sequenceFlow.getTargetFlowElement();
            if (sourceFlowElement instanceof UserTask) {
                UserTask task = (UserTask) sourceFlowElement;
                if (task.getId().equals(sourceActivityId)) {
                    return true;
                }
            } else if (sourceFlowElement instanceof StartEvent) {
                logger.info("结束");
                return false;
            } else {

            }
            flowNode = (FlowNode) sourceFlowElement;
        }
        return false;
    }


    @RequestMapping(method = RequestMethod.POST, value = "queryCommentsByProcessId")
    @ApiOperation(value = "查询该流程的附言列表", notes = "查询该流程的附言列表")
    public FlowableResponse<PageDataResult<ResponseCommentDto>> queryCommentsByProcessId
            (@RequestParam(value = "pageNum") Integer pageNum,
             @RequestParam(value = "pageSize") Integer pageSize,
             @RequestBody ParamCommentDto params) {
        try {
            List<Comment> totalCommentList = taskService.getProcessInstanceComments(params.getProcessId());
            int total = totalCommentList.size();
            if (CollectionUtils.isEmpty(totalCommentList)) {
                return FlowableResponse.success(PageDataResult.empty());
            } else {
                List<ResponseCommentDto> resultList = new ArrayList<>();
                PageDataResult pageDataResult = new PageDataResult(pageNum, pageSize, totalCommentList);

                for (Object c : pageDataResult.getList()) {
                    Comment co = (Comment) c;
                    ResponseCommentDto dto = new ResponseCommentDto();
                    dto.setCommentId(co.getId());
                    dto.setProcessInstanceId(co.getProcessInstanceId());
                    dto.setFullMessage(co.getFullMessage());
                    dto.setUserId(co.getUserId());
                    dto.setTaskId(co.getTaskId());

                    String taskId = co.getTaskId();
                    List<HistoricTaskInstance> tasklist = historyService.createHistoricTaskInstanceQuery().taskId(taskId)
                            .orderByHistoricTaskInstanceEndTime().desc().list();
                    dto.setTaskDefinitionKey(tasklist.get(0).getTaskDefinitionKey());
                    dto.setTaskName(tasklist.get(0).getName());
                    dto.setUserName(flowableEhrEmpService.getChineseName(co.getUserId()));

                    List<Attachment> attachments = taskService.getTaskAttachments(taskId);
                    List<AppendDto> list = new ArrayList<>();
                    for (Attachment att : attachments) {
                        AppendDto app = new AppendDto();
                        app.setAnnexName(att.getName());
                        app.setAnnexUrl(att.getUrl());
                        list.add(app);
                    }
                    dto.setAppendDto(list);

                    dto.setTime(convertTime(co.getTime()));
                    resultList.add(dto);
                }
                pageDataResult.setList(resultList);
                return FlowableResponse.success(pageDataResult);
            }
        } catch (Exception e) {
            logger.error("分页查询评论错误！", e);
            return FlowableResponse.error("分页查询评论错误！e.getMessage=" + e.getMessage());
        }

    }

    @RequestMapping(method = RequestMethod.POST, value = "queryCommentsByProcessIds")
    @ApiOperation(value = "查询该流程的附言列表", notes = "查询该流程的附言列表")
    public FlowableResponse<List<ResponseCommentDto>> queryCommentsByProcessIds
            (@RequestBody List<String> processIds) {
        try {
            List<Comment> totalCommentList = new ArrayList<>();
            if (CollectionUtil.isNotEmpty(processIds)) {
                for (String processId : processIds) {
                    List<Comment> commentList = taskService.getProcessInstanceComments(processId);
                    totalCommentList.addAll(commentList);
                }
            }

            int total = totalCommentList.size();
            if (CollectionUtils.isEmpty(totalCommentList)) {
                return FlowableResponse.success(new ArrayList<>());
            } else {
                List<ResponseCommentDto> resultList = new ArrayList<>();
//                PageDataResult pageDataResult = new PageDataResult(pageNum, pageSize, totalCommentList);

                for (Object c : totalCommentList) {
                    Comment co = (Comment) c;
                    ResponseCommentDto dto = new ResponseCommentDto();
                    dto.setCommentId(co.getId());
                    dto.setProcessInstanceId(co.getProcessInstanceId());
                    dto.setFullMessage(co.getFullMessage());
                    dto.setUserId(co.getUserId());
                    dto.setTaskId(co.getTaskId());

                    String taskId = co.getTaskId();
                    List<HistoricTaskInstance> tasklist = historyService.createHistoricTaskInstanceQuery().taskId(taskId)
                            .orderByHistoricTaskInstanceEndTime().desc().list();
                    dto.setTaskDefinitionKey(tasklist.get(0).getTaskDefinitionKey());
                    dto.setTaskName(tasklist.get(0).getName());
                    dto.setUserName(flowableEhrEmpService.getChineseName(co.getUserId()));

                    List<Attachment> attachments = taskService.getTaskAttachments(taskId);
                    List<AppendDto> list = new ArrayList<>();
                    for (Attachment att : attachments) {
                        AppendDto app = new AppendDto();
                        app.setAnnexName(att.getName());
                        app.setAnnexUrl(att.getUrl());
                        list.add(app);
                    }
                    dto.setAppendDto(list);

                    dto.setTime(convertTime(co.getTime()));
                    resultList.add(dto);
                }
                return FlowableResponse.success(resultList);
            }
        } catch (Exception e) {
            logger.error("分页查询评论错误！", e);
            return FlowableResponse.error("分页查询评论错误！e.getMessage=" + e.getMessage());
        }

    }


    private String convertTime(Date time) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String ctime = sdf.format(time);
        return ctime;
    }


    @RequestMapping(method = RequestMethod.GET, value = "getProcessInfo")
    @ApiOperation(value = "查询流程状态", notes = "查询流程状态")
    public FlowableResponse<ResponseSituationDto> getProcessInfo(@RequestParam(value = "processId") String
                                                                         processId) {

        ResponseSituationDto psd = new ResponseSituationDto();
        List<CreatedTaskInfoDto> createdTaskInfoDtoList = new ArrayList<>();
        HistoricProcessInstance pi = historyService.createHistoricProcessInstanceQuery().processInstanceId(processId).singleResult();
        if (pi == null) {
            logger.error("查询流程状态接口，没查到相应流程，返回。 processId=" + processId);
            return FlowableResponse.success(psd);
        }

        List<HistoricTaskInstance> histask = historyService.createHistoricTaskInstanceQuery().processInstanceId(processId).orderByHistoricTaskInstanceEndTime().asc().list();
        for (HistoricTaskInstance t : histask) {
            CreatedTaskInfoDto info = new CreatedTaskInfoDto();
            info.setTaskId(t.getId());
            info.setStatus("0");
            info.setAssignee(t.getAssignee());
            info.setTaskDefinitionKey(t.getTaskDefinitionKey());
            info.setTaskName(t.getName());
            if (t.getEndTime() != null) {
                info.setStatus("1");
            }
            info.setAssigneeName(flowableEhrEmpService.getChineseName(t.getAssignee()));
            createdTaskInfoDtoList.add(info);
        }

        psd.setStatus("0");
        List<Task> tasklist = taskService.createTaskQuery().processInstanceId(processId).orderByTaskCreateTime().desc().list();

        List<CurrentTaskInfoDto> currentTaskInfoDtoList = new ArrayList<>();
        //如果流程没结束，查询到任务节点
        if (!checkProcessEnd(pi.getId())) {
            if (tasklist != null && tasklist.size() > 0) {
                Map<String, List<String>> map = new HashMap<String, List<String>>();
                Map<String, List<String>> taskidmap = new HashMap<String, List<String>>();
                Map<String, List<String>> datemap = new HashMap<>();

                StringBuffer sbname = new StringBuffer();
                StringBuffer sbkey = new StringBuffer();
                StringBuffer sbid = new StringBuffer();
                StringBuffer sbassignee = new StringBuffer();
                for (int i = 0; i < tasklist.size(); i++) {
                    if (i != (tasklist.size() - 1)) {
                        sbkey.append(tasklist.get(i).getTaskDefinitionKey() + "|");
                        sbname.append(tasklist.get(i).getName() + "|");
                        sbassignee.append(tasklist.get(i).getAssignee() + "|");
                        sbid.append(tasklist.get(i).getId() + "|");

                        String key = tasklist.get(i).getTaskDefinitionKey() + "|" + tasklist.get(i).getName();
                        List<String> assigneeList = new ArrayList<>();
                        List<String> taskIdList = new ArrayList<>();
                        List<String> dateList = new ArrayList<>();

                        if (map.get(key) != null) {
                            assigneeList = map.get(key);
                        }
                        assigneeList.add(tasklist.get(i).getAssignee());
                        map.put(key, assigneeList);

                        if (taskidmap.get(key) != null) {
                            taskIdList = taskidmap.get(key);
                        }
                        taskIdList.add(tasklist.get(i).getId());
                        taskidmap.put(key, taskIdList);
                        if (datemap.get(key) != null) {
                            dateList = datemap.get(key);
                        }
                        dateList.add(convertTime(tasklist.get(i).getCreateTime()));
                        datemap.put(key, dateList);
                    } else {
                        sbkey.append(tasklist.get(i).getTaskDefinitionKey());
                        sbname.append(tasklist.get(i).getName());
                        sbassignee.append(tasklist.get(i).getAssignee());
                        sbid.append(tasklist.get(i).getId());

                        String key = tasklist.get(i).getTaskDefinitionKey() + "|" + tasklist.get(i).getName();
                        List<String> assigneeList = new ArrayList<>();
                        List<String> taskIdList = new ArrayList<>();
                        List<String> dateList = new ArrayList<>();
                        if (map.get(key) != null) {
                            assigneeList = map.get(key);
                        }
                        assigneeList.add(tasklist.get(i).getAssignee());
                        map.put(key, assigneeList);

                        if (taskidmap.get(key) != null) {
                            taskIdList = taskidmap.get(key);
                        }
                        taskIdList.add(tasklist.get(i).getId());
                        taskidmap.put(key, taskIdList);
                        if (datemap.get(key) != null) {
                            dateList = datemap.get(key);
                        }
                        dateList.add(convertTime(tasklist.get(i).getCreateTime()));
                        datemap.put(key, dateList);
                    }

                }
                psd.setCurrentTaskDefinitionKey(sbkey.toString());
                psd.setCurrentTaskName(sbname.toString());
                psd.setCurrentTaskId(sbid.toString());
                psd.setCurrentAssignee(sbassignee.toString());
                psd.setCurrentAssigneeName(flowableEhrEmpService.getChineseNameAll(sbassignee.toString(), "|"));
                psd.setStartTime(convertTime(pi.getStartTime()));


                for (Map.Entry<String, List<String>> m : map.entrySet()) {
                    List<String> userid = m.getValue();
                    List<String> username = new ArrayList<>();
                    for (String id : userid) {
                        username.add(flowableEhrEmpService.getChineseName(id));
                    }

                    String[] defname = m.getKey().split("\\|");
                    CurrentTaskInfoDto currentTaskInfoDto = new CurrentTaskInfoDto();
                    currentTaskInfoDto.setCurrentTaskName(defname[1]);
                    currentTaskInfoDto.setCurrentTaskDefinitionKey(defname[0]);
                    currentTaskInfoDto.setCurrentAssigneeList(m.getValue());
                    currentTaskInfoDto.setCurrentAssigneeNameList(username);
                    currentTaskInfoDto.setCurrentTaskIdList(taskidmap.get(m.getKey()));
                    currentTaskInfoDto.setCurrentTaskCreateTimeList(datemap.get(m.getKey()));
                    currentTaskInfoDtoList.add(currentTaskInfoDto);
                }
            }
        } else {
            psd.setStatus("1");
            psd.setEndTime("1");
            List<FlowableDetail> delist = flowableDetailService.findDetailByProcessId(pi.getId());
            if (delist != null && delist.size() > 0) {
                String status = delist.get(0).getProcessStatus();
                //status2为stop手动结束，置状态
                //status3为delete，不会出现在这个接口
                if (("2").equals(status)) {
                    psd.setStatus("2");
                }
            }
        }
        psd.setProcessTitle(pi.getName());
        psd.setProcessId(pi.getId());
        psd.setProcessDefineName(pi.getProcessDefinitionName());
        psd.setProcessDefineKey(pi.getProcessDefinitionKey());
        psd.setStartTime(convertTime(pi.getStartTime()));
        psd.setStartUsername(pi.getStartUserId());
        psd.setStartUserChineseName(flowableEhrEmpService.getChineseName(pi.getStartUserId()));
        psd.setSysid(pi.getTenantId());

        psd.setCreatedTaskInfoDtoList(createdTaskInfoDtoList);
        psd.setCurrentTaskInfoDtoList(currentTaskInfoDtoList);
        return FlowableResponse.success(psd);
    }


    @RequestMapping(method = RequestMethod.GET, value = "setupAssigneeOrVariable")
    @ApiOperation(value = "设置待办人或者变量", notes = "设置待办人或者变量")
    public FlowableResponse setupAssigneeOrVariable(@RequestParam(value = "processId") String processId,
                                                    @RequestParam(value = "key") String key, @RequestParam(value = "value") String value) {

        if (StringUtils.isEmpty(processId) || StringUtils.isEmpty(key) || StringUtils.isEmpty(value)) {
            return FlowableResponse.error("设置待办人或者变量接口，参数有误，返回。");
        }
        ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
        if (pi == null) {
            return FlowableResponse.error("设置待办人接口，未找到相应流程。processId=" + processId);
        }
        runtimeService.setVariable(processId, key, value);
        if (key.contains("Group")) {
            String[] array = value.split(",");
            runtimeService.setVariable(processId, key + "Size", array.length);
        }
        return FlowableResponse.success(key + ":" + value);
    }

    @RequestMapping(method = RequestMethod.POST, value = "setupVariableByProcessId")
    @ApiOperation(value = "设置待办人或者变量", notes = "设置待办人或者变量")
    public FlowableResponse setupVariableByProcessId(@RequestBody ParamSetupVariableDto paramSetupVariableDto) {

        if (MapUtils.isEmpty(paramSetupVariableDto.getSetupMap())) {
            return FlowableResponse.error("设置待办人或者变量接口参数有误！");
        }

        for (Map.Entry<String, Map<String, Object>> map : paramSetupVariableDto.getSetupMap().entrySet()) {
            if (StringUtils.isEmpty(map.getKey()) || MapUtils.isEmpty(map.getValue())) {
                return FlowableResponse.error("设置待办人或者变量接口，参数有误，返回。");
            }
            for (Map.Entry<String, Object> variable : map.getValue().entrySet()) {
                ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(map.getKey()).singleResult();
                if (pi == null) {
                    return FlowableResponse.error("设置待办人接口，未找到相应流程。processId=" + map.getKey());
                }
                runtimeService.setVariable(map.getKey(), variable.getKey(), variable.getValue());
                if (variable.getKey().contains("Group")) {
                    String[] array = variable.getValue().toString().split(",");
                    runtimeService.setVariable(map.getKey(), variable.getKey() + "Size", array.length);
                }
            }
        }
        return FlowableResponse.success(paramSetupVariableDto.toString());
    }

    @RequestMapping(method = RequestMethod.GET, value = "getVariableByProcessId")
    @ApiOperation(value = "获取待办人或者变量", notes = "获取待办人或者变量")
    public FlowableResponse getVariableByProcessId(@RequestParam(value = "processId") String processId) {

        if (StringUtils.isEmpty(processId)) {
            return FlowableResponse.error("获取待办人或者变量接口，参数有误，返回。");
        }
        ProcessInstance pi = null;
        boolean isFind = false;
        Map<String, Object> variablemap = new HashMap<>();
        pi = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
        if (pi == null) {
            HistoricProcessInstance hispi = historyService.createHistoricProcessInstanceQuery().processInstanceId(processId).singleResult();
            if (hispi != null) {
                variablemap = getHistoricVariables(processId);
                isFind = true;
            }
        } else {
            variablemap = runtimeService.getVariables(processId);
            isFind = true;
        }
        if (!isFind) {
            return FlowableResponse.error("获取待办人或者变量，未找到相应流程。processId=" + processId);
        }

        ParamSetupVariableDto paramSetupVariableDto = new ParamSetupVariableDto();
        Map<String, Map<String, Object>> response = new HashMap<>();
        response.put(processId, variablemap);
        paramSetupVariableDto.setSetupMap(response);
        return FlowableResponse.success(paramSetupVariableDto);
    }

    private Map<String, Object> getHistoricVariables(String processInstanceId) {
        Map<String, Object> varMap = new HashMap<>();
        List<HistoricVariableInstance> historicVars = historyService.createHistoricVariableInstanceQuery().processInstanceId(processInstanceId).list();
        historicVars.forEach(var -> varMap.put(var.getVariableName(), var.getValue()));
        return varMap;
    }
//****************************************以下方法目前未用到***********************************************************


    /**
     * 生成流程图
     *
     * @param processId 流程部署id
     */
    @RequestMapping(value = "processDiagramHigh")
    public void genProcessDiagramHigh(HttpServletResponse httpServletResponse, String processId) throws Exception {
        ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
        //流程走完的不显示图
        if (pi == null) {
            return;
        }

        List<HistoricActivityInstance> historyProcess = getHistoryProcess(processId);
        List<String> activityIds = new ArrayList<>();
        List<String> flows = new ArrayList<>();
        //获取流程图
        BpmnModel bpmnModel = repositoryService.getBpmnModel(pi.getProcessDefinitionId());
        for (HistoricActivityInstance hi : historyProcess) {
            String activityType = hi.getActivityType();
//            if (activityType.equals("sequenceFlow") || activityType.equals("exclusiveGateway")) {
//                flows.add(hi.getActivityId());
//            } else if (activityType.equals("userTask") || activityType.equals("startEvent")) {
//                activityIds.add(hi.getActivityId());
//            }
            if (activityType.equals("sequenceFlow")) {
                flows.add(hi.getActivityId());
            }
        }
        List<Task> tasks = taskService.createTaskQuery().processInstanceId(processId).list();
        for (Task task : tasks) {
            activityIds.add(task.getTaskDefinitionKey());
        }
        ProcessEngineConfiguration engConf = processEngine.getProcessEngineConfiguration();
        //定义流程画布生成器
        ProcessDiagramGenerator processDiagramGenerator = engConf.getProcessDiagramGenerator();
        InputStream in = processDiagramGenerator.generateDiagram(bpmnModel, "png", activityIds, flows, engConf.getActivityFontName(), engConf.getLabelFontName(), engConf.getAnnotationFontName(), engConf.getClassLoader(), 1.0, false);
        OutputStream out = null;
        byte[] buf = new byte[1024];
        int legth = 0;
        try {
            out = httpServletResponse.getOutputStream();
            while ((legth = in.read(buf)) != -1) {
                out.write(buf, 0, legth);
            }
        } finally {
            if (in != null) {
                in.close();
            }
            if (out != null) {
                out.close();
            }
        }
    }

    /**
     * 任务历史
     * <p>
     * &#64;param processId 部署id
     */
    public List<HistoricActivityInstance> getHistoryProcess(String processId) {
        List<HistoricActivityInstance> list = historyService // 历史相关Service
                .createHistoricActivityInstanceQuery() // 创建历史活动实例查询
                .processInstanceId(processId) // 执行流程实例id
                .finished()
                .list();
        return list;
    }

    /**
     * 生成流程图
     *
     * @param processId 流程部署id
     */
    @RequestMapping(value = "processDiagramHigh2")
    public void createImage2(HttpServletResponse httpServletResponse, String processId) throws IOException {
        //1.获取当前的流程实例
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
        String processDefinitionId = null;
        List<String> activeActivityIds = null;
        //2.获取所有的历史轨迹对象
        List<HistoricActivityInstance> list = historyService.createHistoricActivityInstanceQuery()
                .processInstanceId(processId).list();
        Map<String, HistoricActivityInstance> hisActivityMap = new HashMap<>();
        list.forEach(historicActivityInstance -> {
            if (!hisActivityMap.containsKey(historicActivityInstance.getActivityId())) {
                hisActivityMap.put(historicActivityInstance.getActivityId(), historicActivityInstance);
            }
        });
        //3. 获取流程定义id和高亮的节点id
        if (processInstance != null) {
            //3.1. 正在运行的流程实例
            processDefinitionId = processInstance.getProcessDefinitionId();
            activeActivityIds = runtimeService.getActiveActivityIds(processId);
        } else {
            //3.2. 已经结束的流程实例
            HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(processId).singleResult();
            processDefinitionId = historicProcessInstance.getProcessDefinitionId();
            activeActivityIds = new ArrayList<>();
            List<EndEvent> endEvents = findEndFlowElement(processDefinitionId);
            List<String> finalActiveActivityIds = activeActivityIds;
            endEvents.forEach(endEvent -> {
                if (hisActivityMap.containsKey(endEvent.getId())) {
                    finalActiveActivityIds.add(endEvent.getId());
                }
            });
        }
        //4. 获取流程定义的所有节点信息
        //List<FlowNode> flowNodes = bpmnModelService.findFlowNodes(processDefinitionId);
        BpmnModel bpmnModel1 = repositoryService.getBpmnModel(processDefinitionId);
        Collection<FlowElement> flowNodes = bpmnModel1.getProcesses().get(0).getFlowElements();
        Map<String, FlowElement> activityMap = flowNodes.stream().collect(Collectors.toMap(FlowElement::getId, t -> t));
        List<String> highLightedFlows = new ArrayList<>();
        //5. 递归得到高亮线
        activeActivityIds.forEach(activeActivityId -> this.getHighLightedFlows(activityMap, hisActivityMap, activeActivityId, highLightedFlows, activeActivityId));
        //6. 获取bpmnModel对象

        //7. 生成图片流
        //获取流程图
        ProcessEngineConfiguration engConf = processEngine.getProcessEngineConfiguration();
        ProcessDiagramGenerator diagramGenerator = engConf.getProcessDiagramGenerator();
        InputStream in = diagramGenerator.generateDiagram(bpmnModel1, "png", activeActivityIds, highLightedFlows, engConf.getActivityFontName(), engConf.getLabelFontName(), engConf.getAnnotationFontName(), engConf.getClassLoader(), 1.0, true);
        //8. 转化成byte便于网络传输
//        byte[] datas = IoUtil.readInputStream(inputStream, "image inputStream name");
//        return datas;
        OutputStream out = null;
        byte[] buf = new byte[1024];
        int legth = 0;
        try {
            out = httpServletResponse.getOutputStream();
            while ((legth = in.read(buf)) != -1) {
                out.write(buf, 0, legth);
            }
        } finally {
            if (in != null) {
                in.close();
            }
            if (out != null) {
                out.close();
            }
        }
    }


    private void getHighLightedFlows(Map flowNodeMap, Map hisActivityMap, String activeActivityId,
                                     List highLightedFlows, String oldActivityId) {
        FlowNode flowNode = (FlowNode) flowNodeMap.get(activeActivityId);
        List<SequenceFlow> incomingFlows = flowNode.getIncomingFlows();
        for (SequenceFlow sequenceFlow : incomingFlows) {
            String sourceRefId = sequenceFlow.getSourceRef();
            if (hisActivityMap.containsKey(sourceRefId) && !oldActivityId.equals(sourceRefId)) {
                highLightedFlows.add(sequenceFlow.getId());
                this.getHighLightedFlows(flowNodeMap, hisActivityMap, sourceRefId, highLightedFlows, oldActivityId);
            } else {
                if (hisActivityMap.containsKey(sourceRefId)) {
                    highLightedFlows.add(sequenceFlow.getId());
                    break;
                }
                break;
            }
        }
    }

    /**
     * 获取任务节点
     *
     * @param node   查询节点选择
     * @param taskId 任务id
     */
    @RequestMapping(value = "getNode")
    @ResponseBody
    public void nextFlowNode(String node, String taskId) {
        Task task = processEngine.getTaskService().createTaskQuery().taskId(taskId).singleResult();
        ExecutionEntity ee = (ExecutionEntity) processEngine.getRuntimeService().createExecutionQuery()
                .executionId(task.getExecutionId()).singleResult();
        // 当前审批节点
        String crruentActivityId = ee.getActivityId();
        BpmnModel bpmnModel = processEngine.getRepositoryService().getBpmnModel(task.getProcessDefinitionId());
        FlowNode flowNode = (FlowNode) bpmnModel.getFlowElement(crruentActivityId);
        // 输出连线
        List<SequenceFlow> outFlows = flowNode.getOutgoingFlows();
        for (SequenceFlow sequenceFlow : outFlows) {
            //当前审批节点
            if ("now".equals(node)) {
                FlowElement sourceFlowElement = sequenceFlow.getSourceFlowElement();
                logger.info("当前节点: id=" + sourceFlowElement.getId() + ",name=" + sourceFlowElement.getName());
            } else if ("next".equals(node)) {
                // 下一个审批节点
                FlowElement targetFlow = sequenceFlow.getTargetFlowElement();
                if (targetFlow instanceof UserTask) {
                    logger.info("下一节点: id=" + targetFlow.getId() + ",name=" + targetFlow.getName());
                }
                // 如果下个审批节点为结束节点
                if (targetFlow instanceof EndEvent) {
                    logger.info("下一节点为结束节点：id=" + targetFlow.getId() + ",name=" + targetFlow.getName());
                }
            }
        }
    }

    /**
     * 获取流程图详细数据，用于前端渲染。
     *
     * @param processId 流程id
     */
    @RequestMapping(method = RequestMethod.GET, value = "getFlowDetail")
    @ResponseBody
    public FlowableResponse<FlowDetailFrontDto> getFlowDetail(@RequestParam String processId) {
        logger.info("获取流程图详细数据，用于前端渲染getFlowDetail, processId : ,{}", processId);
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
        String processDefinitionId = null;
        List<String> activeActivityIds = null;
        //2.获取所有的历史轨迹对象
        List<HistoricActivityInstance> list = historyService.createHistoricActivityInstanceQuery()
                .processInstanceId(processId).list();
        Map<String, HistoricActivityInstance> hisActivityMap = new HashMap<>();
        list.forEach(historicActivityInstance -> {
            if (!hisActivityMap.containsKey(historicActivityInstance.getActivityId())) {
                hisActivityMap.put(historicActivityInstance.getActivityId(), historicActivityInstance);
            }
        });
        //3. 获取流程定义id和高亮的节点id
        Map<String, Object> variablemap;

        List<Comment> totalCommentList = taskService.getProcessInstanceComments(processId);
        Map<String, List<NodeTaskAssignees>> commentMap = new HashMap<>();
        if (!CollectionUtils.isEmpty(totalCommentList)) {
            for (Comment co : totalCommentList) {
                ResponseCommentDto dto = new ResponseCommentDto();
                dto.setCommentId(co.getId());
                dto.setProcessInstanceId(co.getProcessInstanceId());
                dto.setFullMessage(co.getFullMessage());
                dto.setUserId(co.getUserId());
                dto.setTaskId(co.getTaskId());

                String taskId = co.getTaskId();
                List<HistoricTaskInstance> tasklist = historyService.createHistoricTaskInstanceQuery().taskId(taskId)
                        .orderByHistoricTaskInstanceEndTime().desc().list();
                dto.setTaskDefinitionKey(tasklist.get(0).getTaskDefinitionKey());
                dto.setTaskName(tasklist.get(0).getName());
                dto.setUserName(flowableEhrEmpService.getChineseName(co.getUserId()));

                List<Attachment> attachments = taskService.getTaskAttachments(taskId);
                List<AppendDto> list111 = new ArrayList<>();
                for (Attachment att : attachments) {
                    AppendDto app = new AppendDto();
                    app.setAnnexName(att.getName());
                    app.setAnnexUrl(att.getUrl());
                    list111.add(app);
                }
                dto.setAppendDto(list111);

                dto.setTime(convertTime(co.getTime()));
                List<NodeTaskAssignees> nodeTaskAssignees = new ArrayList<>();
                if (commentMap.containsKey(dto.getTaskDefinitionKey())) {
                    nodeTaskAssignees = commentMap.get(dto.getTaskDefinitionKey());
                }
                nodeTaskAssignees.add(NodeTaskAssignees.builder().name(dto.getUserName()).account(dto.getUserId()).time(dto.getTime()).build());
                commentMap.put(dto.getTaskDefinitionKey(), nodeTaskAssignees);

            }
        }

        if (processInstance != null) {
            //3.1. 正在运行的流程实例
            processDefinitionId = processInstance.getProcessDefinitionId();
            activeActivityIds = runtimeService.getActiveActivityIds(processId);
            variablemap = runtimeService.getVariables(processId);
        } else {
            //3.2. 已经结束的流程实例
            HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(processId).singleResult();
            processDefinitionId = historicProcessInstance.getProcessDefinitionId();
            variablemap = getHistoricVariables(processId);
            activeActivityIds = new ArrayList<>();
            List<EndEvent> endEvents = findEndFlowElement(processDefinitionId);
            List<String> finalActiveActivityIds = activeActivityIds;
            endEvents.forEach(endEvent -> {
                if (hisActivityMap.containsKey(endEvent.getId())) {
                    finalActiveActivityIds.add(endEvent.getId());
                }
            });
        }
        //4. 获取流程定义的所有节点信息
        BpmnModel bpmnModel1 = repositoryService.getBpmnModel(processDefinitionId);
        Collection<FlowElement> flowNodes = bpmnModel1.getProcesses().get(0).getFlowElements();
        String name = bpmnModel1.getProcesses().get(0).getName();
        String id = bpmnModel1.getProcesses().get(0).getId();

        Map<String, FlowElement> activityMap = flowNodes.stream().collect(Collectors.toMap(FlowElement::getId, t -> t));
        List<String> highLightedFlows = new ArrayList<>();

        //5. 递归得到高亮线
        activeActivityIds.forEach(activeActivityId -> this.getHighLightedFlows(activityMap, hisActivityMap, activeActivityId, highLightedFlows, activeActivityId));
        //6. 获取bpmnModel对象

        Set<String> hasDoneNodes = hisActivityMap.keySet();
        Set<String> activeNodes = new HashSet<>(activeActivityIds);
        hasDoneNodes.removeAll(activeNodes);
        Map<String, GraphicInfo> locationMap = bpmnModel1.getLocationMap();
        FlowDetailFrontDto flowDetailFrontDto = buildFlowDetailDto(flowNodes, hasDoneNodes, activeNodes, variablemap, commentMap, locationMap);
        flowDetailFrontDto.setFlowName(name);
        flowDetailFrontDto.setFlowDefinitionKey(id);
        //后处理，补充节点/边的坐标
        flowDetailFrontDto.getNodes().forEach(e -> {
            e.setNodeX(Objects.isNull(locationMap.get(e.getNodeTaskKey())) ? null : locationMap.get(e.getNodeTaskKey()).getX());
            e.setNodeY(Objects.isNull(locationMap.get(e.getNodeTaskKey())) ? null : locationMap.get(e.getNodeTaskKey()).getY());
        });
        flowDetailFrontDto.getSubProcessNodes().forEach(e -> {
            e.getNodes().forEach(f -> {
                f.setNodeX(Objects.isNull(locationMap.get(f.getNodeTaskKey())) ? null : locationMap.get(f.getNodeTaskKey()).getX());
                f.setNodeY(Objects.isNull(locationMap.get(f.getNodeTaskKey())) ? null : locationMap.get(f.getNodeTaskKey()).getY());
            });
        });

        Map<String, List<GraphicInfo>> flowLocationMap = bpmnModel1.getFlowLocationMap();
        flowDetailFrontDto.getEdges().forEach(e -> {
            if (flowLocationMap.get(e.getEdgeId()).size() > 2) {
                List<GraphicInfo> graphicInfos = flowLocationMap.get(e.getEdgeId());
                List<GraphicInfo> sub = CollectionUtil.sub(graphicInfos, 1, graphicInfos.size() - 1);
                List<FrontFlowEdgeFoldPoint> points = sub.stream().map(f -> new FrontFlowEdgeFoldPoint(f.getX(), f.getY())).collect(Collectors.toList());
                e.setFoldPointList(points);
            }
        });
        flowDetailFrontDto.getSubProcessNodes().forEach(e -> {
            e.getEdges().forEach(f -> {
                if (flowLocationMap.get(f.getEdgeId()).size() > 2) {
                    List<GraphicInfo> graphicInfos = flowLocationMap.get(f.getEdgeId());
                    List<GraphicInfo> sub = CollectionUtil.sub(graphicInfos, 1, graphicInfos.size() - 1);
                    List<FrontFlowEdgeFoldPoint> points = sub.stream().map(p -> new FrontFlowEdgeFoldPoint(p.getX(), p.getY())).collect(Collectors.toList());
                    f.setFoldPointList(points);
                }
            });
        });
        return FlowableResponse.success(flowDetailFrontDto);
    }

    public FlowDetailFrontDto buildFlowDetailDto(Collection<FlowElement> flowNodes, Set<String> hasDoneNodes, Set<String> activeNodes, Map<String, Object> variablemap, Map<String, List<NodeTaskAssignees>> commentMap, Map<String, GraphicInfo> locationMap) {
        FlowDetailFrontDto dto = new FlowDetailFrontDto();
        List<FrontFlowNode> nodes = new ArrayList<>();
        List<FlowDetailFrontDto> SubProcessNodes = new ArrayList<>();
        List<FrontFlowEdge> edges = new ArrayList<>();
        double xmax = Double.MIN_VALUE;
        double xmin = Double.MAX_VALUE;
        double ymax = Double.MIN_VALUE;
        double ymin = Double.MAX_VALUE;
        Iterator<FlowElement> iterator = flowNodes.iterator();
        while (iterator.hasNext()) {
            FlowElement e = iterator.next();
            if (e instanceof UserTask) {
                UserTask task = (UserTask) e;
                FrontFlowNode node = new FrontFlowNode();
                node.setNodeTaskKey(task.getId());
                node.setNodeTaskName(task.getName());
                node.setNodeTaskType("UserTask");
                if (hasDoneNodes.contains(task.getId())) {
                    node.setNodeTaskStatus(FlowableConstant.NODE_ARRIVED);
                } else if (activeNodes.contains(task.getId())) {
                    node.setNodeTaskStatus(FlowableConstant.NODE_ACTIVE);
                } else {
                    node.setNodeTaskStatus(FlowableConstant.NODE_NO_ARRIVED);
                }

                if (commentMap.containsKey(task.getId())) {
                    if (StrUtil.equals("beginTask", task.getId())) {
                        String assignee = task.getAssignee();
                        assignee = assignee.substring(2, assignee.length() - 1);
                        String str = (String) variablemap.get(assignee);
                        List<NodeTaskAssignees> nodeTaskAssignees = commentMap.get(task.getId());
                        if (CollectionUtils.isNotEmpty(nodeTaskAssignees)) {
                            nodeTaskAssignees.forEach(nta -> nta.setStatus("1"));
                        }
                        node.setAssignees(nodeTaskAssignees);
                    } else {
                        String assignee = task.getAssignee();
                        assignee = assignee.substring(2, assignee.length() - 1) + "Group";
                        Set<String> set = (HashSet<String>) variablemap.get(assignee);
                        if (CollectionUtils.isNotEmpty(set)) {
                            List<NodeTaskAssignees> nodeTaskAssignees = commentMap.get(task.getId());
                            if (CollectionUtils.isNotEmpty(nodeTaskAssignees)) {
                                nodeTaskAssignees.forEach(nta -> {
                                    nta.setStatus("1");
                                    nta.setName(flowableEhrEmpService.getChineseName(nta.getAccount()));
                                    set.remove(nta.getAccount());
                                });
                                if (CollectionUtils.isNotEmpty(set)) {
                                    set.forEach(str -> {
                                        NodeTaskAssignees nodesign = NodeTaskAssignees.builder().name(flowableEhrEmpService.getChineseName(str)).account(str).build();
                                        nodesign.setStatus("0");
                                        nodeTaskAssignees.add(nodesign);
                                    });
                                }
                            }
                            node.setAssignees(nodeTaskAssignees);
                        } else {
                            System.out.println(assignee);
                        }
                    }
                }
                nodes.add(node);
                xmax = Math.max(locationMap.get(task.getId()).getX(), xmax);
                xmin = Math.min(locationMap.get(task.getId()).getX(), xmin);
                ymax = Math.max(locationMap.get(task.getId()).getY(), ymax);
                ymin = Math.min(locationMap.get(task.getId()).getY(), ymin);
            } else if (e instanceof StartEvent) {// 开始节点， 不存在会签人
                StartEvent task = (StartEvent) e;
                FrontFlowNode node = new FrontFlowNode();
                node.setNodeTaskKey(task.getId());
                node.setNodeTaskName(task.getName());
                node.setNodeTaskType("StartEvent");
                if (hasDoneNodes.contains(task.getId())) {
                    node.setNodeTaskStatus(FlowableConstant.NODE_ARRIVED);
                } else if (activeNodes.contains(task.getId())) {
                    node.setNodeTaskStatus(FlowableConstant.NODE_ACTIVE);
                } else {
                    node.setNodeTaskStatus(FlowableConstant.NODE_NO_ARRIVED);
                }
                nodes.add(node);
                xmax = Math.max(locationMap.get(task.getId()).getX(), xmax);
                xmin = Math.min(locationMap.get(task.getId()).getX(), xmin);
                ymax = Math.max(locationMap.get(task.getId()).getY(), ymax);
                ymin = Math.min(locationMap.get(task.getId()).getY(), ymin);
            } else if (e instanceof EndEvent) {// 结束节点， 不存在会签人
                EndEvent task = (EndEvent) e;
                FrontFlowNode node = new FrontFlowNode();
                node.setNodeTaskKey(task.getId());
                node.setNodeTaskName(task.getName());
                node.setNodeTaskType("EndEvent");
                if (hasDoneNodes.contains(task.getId())) {
                    node.setNodeTaskStatus(FlowableConstant.NODE_ARRIVED);
                } else if (activeNodes.contains(task.getId())) {
                    node.setNodeTaskStatus(FlowableConstant.NODE_ACTIVE);
                } else {
                    node.setNodeTaskStatus(FlowableConstant.NODE_NO_ARRIVED);
                }
                nodes.add(node);
                xmax = Math.max(locationMap.get(task.getId()).getX(), xmax);
                xmin = Math.min(locationMap.get(task.getId()).getX(), xmin);
                ymax = Math.max(locationMap.get(task.getId()).getY(), ymax);
                ymin = Math.min(locationMap.get(task.getId()).getY(), ymin);
            } else if (e instanceof ParallelGateway) {
                ParallelGateway task = (ParallelGateway) e;
                FrontFlowNode node = new FrontFlowNode();
                node.setNodeTaskKey(task.getId());
                node.setNodeTaskName(task.getName());
                node.setNodeTaskType("ParallelGateway");
                if (hasDoneNodes.contains(task.getId())) {
                    node.setNodeTaskStatus(FlowableConstant.NODE_ARRIVED);
                } else if (activeNodes.contains(task.getId())) {
                    node.setNodeTaskStatus(FlowableConstant.NODE_ACTIVE);
                } else {
                    node.setNodeTaskStatus(FlowableConstant.NODE_NO_ARRIVED);
                }
                nodes.add(node);
                xmax = Math.max(locationMap.get(task.getId()).getX(), xmax);
                xmin = Math.min(locationMap.get(task.getId()).getX(), xmin);
                ymax = Math.max(locationMap.get(task.getId()).getY(), ymax);
                ymin = Math.min(locationMap.get(task.getId()).getY(), ymin);
            } else if (e instanceof ExclusiveGateway) {
                ExclusiveGateway task = (ExclusiveGateway) e;
                FrontFlowNode node = new FrontFlowNode();
                node.setNodeTaskKey(task.getId());
                node.setNodeTaskName(task.getName());
                node.setNodeTaskType("ExclusiveGateway");
                if (hasDoneNodes.contains(task.getId())) {
                    node.setNodeTaskStatus(FlowableConstant.NODE_ARRIVED);
                } else if (activeNodes.contains(task.getId())) {
                    node.setNodeTaskStatus(FlowableConstant.NODE_ACTIVE);
                } else {
                    node.setNodeTaskStatus(FlowableConstant.NODE_NO_ARRIVED);
                }
                nodes.add(node);
                xmax = Math.max(locationMap.get(task.getId()).getX(), xmax);
                xmin = Math.min(locationMap.get(task.getId()).getX(), xmin);
                ymax = Math.max(locationMap.get(task.getId()).getY(), ymax);
                ymin = Math.min(locationMap.get(task.getId()).getY(), ymin);
            } else if (e instanceof SubProcess) {
                SubProcess task = (SubProcess) e;
                FlowDetailFrontDto flowDetailFrontDto = buildFlowDetailDto(task.getFlowElements(), hasDoneNodes, activeNodes, variablemap, commentMap, locationMap);
                flowDetailFrontDto.setFlowName(task.getName());
                flowDetailFrontDto.setFlowDefinitionKey(task.getId());
                SubProcessNodes.add(flowDetailFrontDto);
            } else if (e instanceof SequenceFlow) {
                FrontFlowEdge edge = new FrontFlowEdge();
                SequenceFlow task = (SequenceFlow) e;
                edge.setEdgeId(task.getId());
                edge.setFromNodeTaskKey(task.getSourceRef());
                edge.setToNodeTaskKey(task.getTargetRef());
                edges.add(edge);
            }
        }
        dto.setMaxX(xmax);
        dto.setMinX(xmin);
        dto.setMaxY(ymax);
        dto.setMinY(ymin);
        dto.setEdges(edges);
        dto.setNodes(nodes);
        dto.setSubProcessNodes(SubProcessNodes);
        return dto;
    }

    /**
     * 通过流程的taskid 转发当前流程 (仅针对未结束的流程)
     * 效果:增加一个无关联的节点,绑定处理人. 该节点是否处理会影响当前流程是否接触.
     *
     * @param param the param
     */


    @RequestMapping(method = RequestMethod.POST, value = "/forwardByTask")
    @ApiOperation(value = "动态更新By Task", notes = "动态更新By Task")
    public FlowableResponse<ForwardFlowableResponse> forwardFlowableByTask(@RequestBody ForwardFlowableParamDto param) {
        if (CollectionUtil.isEmpty(param.getUserList()) || StrUtil.isBlank(param.getTaskId())) {
            throw new RuntimeException("转发接收人用户账号为空或任务Id为空!");
        }
        ForwardFlowableResponse forwardResponse = new ForwardFlowableResponse();

        Task task = processEngine.getTaskService().createTaskQuery().taskId(param.getTaskId()).singleResult();
        String processInstanceId = task.getProcessInstanceId();
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        BpmnModel bpmnModel = processEngine.getRepositoryService().getBpmnModel(processInstance.getProcessDefinitionId());
        Process process = bpmnModel.getProcesses().get(0);
        try {
            List<String> recvAccountNameList = new ArrayList<>();
            List<String> forwardNewTaskIdList = new ArrayList<>();
            for (String recvAccount : param.getUserList()) {
                String forwardNewTaskId = updateFlowForForward(task, recvAccount, process);
                logger.info("任务{}-{}，增加转发处理-{}", task.getName(), task.getId(), recvAccount);
                forwardNewTaskIdList.add(forwardNewTaskId);

                FlowableEhrEmp userInfo = flowableEhrEmpService.getUserInfo(recvAccount);
                if (ObjectUtil.isNotNull(userInfo)) {
                    recvAccountNameList.add(userInfo.getName());//转发接收人的中文名字
                } else {
                    recvAccountNameList.add(recvAccount);
                }
            }

            //增加转发任务备注
            String defaultComment = StrUtil.isEmpty(param.getComment()) ? "转发任务" : param.getComment();
            String forwardComment = String.format("%s，转发接收人：%s", defaultComment, String.join(",", recvAccountNameList));
            Authentication.setAuthenticatedUserId(task.getAssignee());//转发人员信息
            taskService.addComment(task.getId(), task.getProcessInstanceId(), forwardComment);
            flowableCommentSupplementService.signTask(task.getId());
            logger.info("转发任务完成，新增转发任务ID:{}", String.join(",", forwardNewTaskIdList));

            forwardResponse.setTaskIdList(forwardNewTaskIdList);
            return FlowableResponse.success(forwardResponse);//返回转发新建任务ID列表
        } catch (Exception e) {
            throw new RuntimeException("流程转发-动态更新节点失败!" + e.getMessage());
        }
    }


    /**
     * taskid 标识的任务转发，增加forwardTaskAssignee这个人员进行转发任务处理
     *
     * @param forwardTaskAssignee 转发任务接收人
     * @return 转发任务id
     */
    private String updateFlowForForward(Task task, String forwardTaskAssignee, Process process) {
        if (task == null || StrUtil.isEmpty(forwardTaskAssignee)) {
            return "";
        }
        String processInstanceId = task.getProcessInstanceId();
        String newDynamicTaskId = "ForwardTask-" + UUID.randomUUID();
        logger.info("流程-{}-任务{}-{}-新增临时节点-{}", process.getName(), task.getName(), task.getId(), newDynamicTaskId);

        DynamicUserTaskBuilder dynamicUserTaskBuilder = new DynamicUserTaskBuilder();
        dynamicUserTaskBuilder.setId(newDynamicTaskId);
        String assignee = task.getAssignee();
        FlowableEhrEmp userInfo = flowableEhrEmpService.getUserInfo(assignee);
        if (ObjectUtil.isNotNull(userInfo)) {
            assignee = userInfo.getName();//转发发起人的中文名字
        }
        dynamicUserTaskBuilder.setName(task.getName() + "-" + assignee + "-转发");
        dynamicUserTaskBuilder.setAssignee(forwardTaskAssignee);//把任务转发给此人
        processEngine.getManagementService().executeCommand(new CustomInjectUserTaskInProcessInstanceCmd(processInstanceId
                , dynamicUserTaskBuilder, process.getFlowElement(task.getTaskDefinitionKey())));

        logger.info("流程-{}-任务{}-{}-新增临时节点-{}-新增完成OK.", process.getName(), task.getName(), task.getId(), newDynamicTaskId);

        return newDynamicTaskId;
    }

    /**
     * 新回退方法，兼容前置节点存在skip_expression==true的情况
     */
    @RequestMapping(method = RequestMethod.POST, value = "/newRollback")
    @ApiOperation(value = "回退接口", notes = "回退接口")
    public FlowableResponse newRollback(@RequestBody ParamRollbackDto params) {
        String processid = null;
        String taskId;
        String sysid;
        String comment;
        List<String> targetList = new ArrayList<>();
        List<String> sourceList = new ArrayList<>();
        List<String> userList = new ArrayList<>();
        List<String> taskList = new ArrayList<>();
        try {
            comment = params.getComment();
            taskId = params.getTaskId();
            if (StrUtil.isEmpty(taskId)) {
                return FlowableResponse.error("任务流程回退失败，taskId不能为空");
            }
            sysid = params.getSysid();
            if (StrUtil.isEmpty(sysid)) {
                return FlowableResponse.error("任务流程回退失败，sysid不能为空");
            }
        } catch (Exception e) {
            return FlowableResponse.error("任务流程回退失败，参数获取异常！ message=" + e.getMessage());
        }

        try {
            Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
            processid = task.getProcessInstanceId();
            ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processid).singleResult();
            ExecutionEntity ee = (ExecutionEntity) processEngine.getRuntimeService().createExecutionQuery()
                    .executionId(task.getExecutionId()).singleResult();
            Set<String> ingKeySet = processEngine.getRuntimeService().createExecutionQuery().processInstanceId(processid).list().stream().map(Execution::getActivityId).filter(StrUtil::isNotEmpty).collect(Collectors.toSet());
            // 当前审批节点
            String currentActivityId = ee.getActivityId();//acitivtyId，即流程节点ID
            BpmnModel bpmnModel = repositoryService.getBpmnModel(ee.getProcessDefinitionId());
            Map<String, FlowElement> flowElementMap = bpmnModel.getMainProcess().getFlowElementMap();
            //回去 targetnode 到 source node 的map， source可能存在多个。
            Map<String, List<String>> target2sourceMap = new HashMap<>();
            List<FlowElement> collect = flowElementMap.values().stream().filter(e -> e instanceof SequenceFlow).collect(Collectors.toList());
            for (FlowElement flowElement : collect) {
                String targetRef = ((SequenceFlow) flowElement).getTargetRef();
                String sourceRef = ((SequenceFlow) flowElement).getSourceRef();
                if (target2sourceMap.containsKey(targetRef)) {
                    List<String> strings = target2sourceMap.get(targetRef);
                    strings.add(sourceRef);
                } else {
                    target2sourceMap.put(targetRef, CollectionUtil.newArrayList(sourceRef));
                }
            }

            List<HistoricActivityInstance> historyList = historyService.createHistoricActivityInstanceQuery().processInstanceId(processid).orderByHistoricActivityInstanceStartTime().desc().list();
            //获取真实前置节点
            List<String> sourceElement = getSourceElement(currentActivityId, historyList, target2sourceMap, historyList.get(0).getStartTime());
            if (CollectionUtils.isEmpty(sourceElement)) {
                return FlowableResponse.error("未查询到起始task");//startEvent 或 子流程的 suPprocessStartEvent
            }
            Set<String> userTaskSet = flowElementMap.values().stream().filter(e -> (e instanceof UserTask)).map(e -> (UserTask) e).map(UserTask::getId).collect(Collectors.toSet());
            Set<String> unionSet = new HashSet<>(CollectionUtil.intersection(ingKeySet, userTaskSet));
            //获取将要被移除的节点，用于删除执行实例Execution
            Set<String> removeSet = new HashSet<>();
            ArrayList<String> ingKeyList = new ArrayList<>(unionSet);
            for (String s : ingKeyList) {
                for (String value : sourceElement) {
                    if (isBelongtoSource(s, value, target2sourceMap)) {
                        removeSet.add(s);
                        break;
                    }
                }
            }
            targetList.addAll(removeSet);
            //move关系：
            // 1:1（单点回退到1个前置节点）
            // 1:n（单点回退到多个前置节点）
            // n:1（单点回退到1个前置节点，同时触发其余子节点回退）
            // n:n（单点回退到多个前置节点，同时触发其余子节点回退）
            //添加comment
            if (StringUtils.isEmpty(params.getUserId())) {
                Authentication.setAuthenticatedUserId(task.getAssignee());
            } else {
                Authentication.setAuthenticatedUserId(params.getUserId());
            }
            if (StrUtil.isNotBlank(comment)) {
                taskService.addComment(taskId, processid, FlowableConstant.BACK_TAG + comment);
                flowableCommentSupplementService.signTask(taskId);
            } else {
                taskService.addComment(taskId, processid, FlowableConstant.BACK_TAG);
                flowableCommentSupplementService.signTask(taskId);
            }
            logger.info("sourceElement长度：" + sourceElement.size());
            if (sourceElement.size() == 1) {
                if (removeSet.size() == 1) {
                    // 终止流程.基协备案回退. 需要移除 评审清算结果公告 后的 网关执行实例
                    List<String> currentExecutionIds = new ArrayList<>();
                    List<Execution> executions = runtimeService.createExecutionQuery().parentId(task.getProcessInstanceId()).list();
                    for (Execution execution : executions) {
                        logger.info("并行网关节点数：" + execution.getActivityId());
                        ExecutionEntity entity = (ExecutionEntity) execution;
                        if (isBelongtoSourceNew(execution.getId(), sourceElement.get(0), target2sourceMap)) {
                            currentExecutionIds.add(execution.getId());
                        }
                    }
                    if (CollUtil.isEmpty(currentExecutionIds)) {
                        runtimeService.createChangeActivityStateBuilder().processInstanceId(processid).moveActivityIdTo(currentActivityId, sourceElement.get(0)).changeState();
                    } else {
                        runtimeService.createChangeActivityStateBuilder().processInstanceId(task.getProcessInstanceId())
                                .moveExecutionsToSingleActivityId(currentExecutionIds, sourceElement.get(0)).changeState();
                    }
                } else if (removeSet.size() > 1) {
                    List<String> currentExecutionIds = new ArrayList<>();
                    List<Execution> executions = runtimeService.createExecutionQuery().parentId(task.getProcessInstanceId()).list();
                    for (Execution execution : executions) {
                        logger.info("并行网关节点数：" + execution.getActivityId());
                        ExecutionEntity entity = (ExecutionEntity) execution;
                        if (isBelongtoSourceNew(execution.getId(), sourceElement.get(0), target2sourceMap)) {
                            currentExecutionIds.add(execution.getId());
                        }
                    }
                    runtimeService.createChangeActivityStateBuilder().processInstanceId(task.getProcessInstanceId())
                            .moveExecutionsToSingleActivityId(currentExecutionIds, sourceElement.get(0)).changeState();
                }
            } else if (sourceElement.size() > 1) {
                if (removeSet.size() == 1) {
                    runtimeService.createChangeActivityStateBuilder().processInstanceId(processid).moveSingleActivityIdToActivityIds(currentActivityId, sourceElement).changeState();
                } else if (removeSet.size() > 1) {
                    for (String str : sourceElement) {
                        List<String> currentExecutionIds = new ArrayList<>();
                        List<Execution> executions = runtimeService.createExecutionQuery().parentId(task.getProcessInstanceId()).list();
                        for (Execution execution : executions) {
                            logger.info("并行网关节点数：" + execution.getActivityId());
                            ExecutionEntity entity = (ExecutionEntity) execution;
                            if (isBelongtoSourceNew(execution.getId(), str, target2sourceMap)) {
                                currentExecutionIds.add(execution.getId());
                            }
                        }
                        //无对应 currentExecutionIds 时, 自主重建任务
                        if (CollUtil.isNotEmpty(currentExecutionIds)) {
                            runtimeService.createChangeActivityStateBuilder().processInstanceId(task.getProcessInstanceId())
                                    .moveExecutionsToSingleActivityId(currentExecutionIds, str).changeState();
                        } else {
                            //!!!!!!去重, 按创建时间排序,取最早任务的 任务名称.
                            List<HistoricTaskInstance> list = historyService.createHistoricTaskInstanceQuery().processInstanceId(processid).taskDefinitionKey(str).orderByTaskCreateTime().asc().list();
                            Set<String> assigneeList = list.stream().map(HistoricTaskInstance::getAssignee).collect(Collectors.toSet());
                            util.reBuildMulTask(new ArrayList<>(assigneeList), str, CollUtil.getFirst(list).getName(), processid);
                        }
                    }
                }
            }
            sourceList.addAll(sourceElement);
            Set<String> userSet = new HashSet();
            Set<String> taskSet = new HashSet();
            processService.callBackRemindActivitors(processid, sourceList, targetList, userSet, taskSet);
            userList.addAll(userSet);
            taskList.addAll(taskSet);
            //入库
            flowableDetailService.addProcessInstanceByTask(task, pi, sysid, null, pi.getName(), "rollback");
        } catch (Exception e) {
            logger.error("任务流程回退失败，请检查！taskid=" + taskId + ",processid=" + processid, e);
            return FlowableResponse.error("任务流程回退失败", "回退失败，请检查！taskid=" + taskId + ",processid=" + processid + ",e.getMessage=" + e.getMessage());
        }
        return FlowableResponse.success(new ResponseMsgDto("任务流程回退成功", userList, taskList));
    }

    /**
     * 获取真实前置节点
     */
    private List<String> getSourceElement(String currentActivityId, List<HistoricActivityInstance> historyList, Map<String, List<String>> target2sourceMap, Date opTime) {
        List<String> res = new ArrayList<>();
        List<String> strings = target2sourceMap.get(currentActivityId);
        if (CollectionUtils.isEmpty(strings)) {
            return res;
        }
        if (strings.size() == 1) {
            HistoricActivityInstance historicActivityInstance = historyList.stream().filter(e -> ObjectUtil.isNotNull(e.getEndTime()) && StrUtil.equals(strings.get(0), e.getActivityId()) && DateUtil.compare(e.getStartTime(), opTime) <= 0).findFirst().get();
            if (historicActivityInstance.getDurationInMillis() < 50) {
                res.addAll(getSourceElement(strings.get(0), historyList, target2sourceMap, historicActivityInstance.getStartTime()));
            } else {
                res.add(historicActivityInstance.getActivityId());
            }
        } else {
            Set<String> set = new HashSet<>();
            for (int i = 0; i < strings.size(); i++) {
                int finalI = i;
                HistoricActivityInstance historicActivityInstance = historyList.stream().filter(e -> ObjectUtil.isNotNull(e.getEndTime()) && StrUtil.equals(strings.get(finalI), e.getActivityId()) && DateUtil.compare(e.getStartTime(), opTime) <= 0).findFirst().get();
                if (historicActivityInstance.getDurationInMillis() < 50) {
                    set.addAll(getSourceElement(strings.get(i), historyList, target2sourceMap, historicActivityInstance.getStartTime()));
                } else {
                    set.add(historicActivityInstance.getActivityId());
                }
            }

            if (set.size() > 1) {
                String[] arr = set.toArray(new String[0]);
                for (int i = 0; i < arr.length - 1; i++) {
                    for (int j = i + 1; j < arr.length; j++) {
                        if (arr[i] != null && arr[j] != null) {
                            if (isBelongtoSource(arr[i], arr[j], target2sourceMap)) {
                                arr[j] = null;
                                continue;
                            }
                            if (isBelongtoSource(arr[j], arr[i], target2sourceMap)) {
                                arr[i] = null;
                                break;
                            }
                        }
                    }
                }
                res.addAll(Arrays.stream(arr).filter(StrUtil::isNotEmpty).collect(Collectors.toSet()));
            } else {
                res.addAll(set);
            }
        }
        return res;
    }
    //原逻辑场景覆盖不全面。  because inflow只取一个: FlowElement sourceFlowElement = inFlows.get(0).getSourceFlowElement();

    /**
     * 判断当前节点是否是 source的后置节点。
     * 较旧版： 通过target2sourceMap取判断；解决 取inflows时遗漏问题。FlowElement sourceFlowElement = inFlows.get(0).getSourceFlowElement();
     */
    private boolean isBelongtoSource(String crruentActivityId, String sourceActivityId, Map<String, List<String>> target2sourceMap) {
        int count = 0;
        return isBelongtoSourceByFlowMap(target2sourceMap.get(crruentActivityId), sourceActivityId, target2sourceMap, count);
//        FlowNode flowNode = (FlowNode) bpmnModel.getFlowElement(crruentActivityId);
//        while (flowNode.getIncomingFlows() != null) {
//            List<SequenceFlow> inFlows = flowNode.getIncomingFlows();
//            FlowElement sourceFlowElement = inFlows.get(0).getSourceFlowElement();
//            if (sourceFlowElement instanceof UserTask) {
//                UserTask task = (UserTask) sourceFlowElement;
//                if (task.getId().equals(sourceActivityId)) {
//                    return true;
//                }
//            } else if (sourceFlowElement instanceof StartEvent) {
//                logger.info("结束");
//                return false;
//            }
//            flowNode = (FlowNode) sourceFlowElement;
//        }
//        return false;
    }

    /**
     * 判断当前节点是否是 source的后置节点。
     */
    //sourceList = target2sourceMap.get(crruentActivityId);
    private boolean isBelongtoSourceByFlowMap(List<String> sourceList, String sourceActivityId, Map<String, List<String>> target2sourceMap, int count) {
        if (CollectionUtil.isEmpty(sourceList) || count > 200) {
            return false;
        }
        Set<String> set = new HashSet<>();
        for (int i = 0; i < sourceList.size(); i++) {
            if (sourceList.get(i).equals(sourceActivityId)) {
                return true;
            }
            if (sourceList.get(i).equals("startEvent") || sourceList.get(i).equals("subProcessStartEvent")) {
                continue;
            }
            set.addAll(target2sourceMap.get(sourceList.get(i)));
        }
        logger.info("isBelongtoSourceByFlowMap--sourceList:" + CollUtil.join(set, ","));
        count++;
        return isBelongtoSourceByFlowMap(new ArrayList<>(set), sourceActivityId, target2sourceMap, count);
    }

    /**
     * 判断当前节点是否是 source的后置节点。
     * param:currentExecuteId 执行实例id
     */
    private boolean isBelongtoSourceNew(String currentExecuteId, String sourceActivityId, Map<String, List<String>> target2sourceMap) {
        ExecutionEntity currentExecute = (ExecutionEntity) processEngine.getRuntimeService().createExecutionQuery()
                .executionId(currentExecuteId).singleResult();
        // 当前节点
        String crruentActivityId = currentExecute.getActivityId();
        int count = 0;
        return isBelongtoSourceByFlowMap(target2sourceMap.get(crruentActivityId), sourceActivityId, target2sourceMap, count);
    }

    @RequestMapping(method = RequestMethod.GET, value = "/getAllSourceList")
    @ApiOperation(value = "查询可回退节点接口", notes = "查询可回退节点接口")
    public FlowableResponse getAllSourceList(@RequestParam String taskId) {
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if (ObjectUtil.isNull(task)) {
            return FlowableResponse.error("taskId不存在！");
        }
        String processid = task.getProcessInstanceId();
        ExecutionEntity ee = (ExecutionEntity) processEngine.getRuntimeService().createExecutionQuery()
                .executionId(task.getExecutionId()).singleResult();
        String currentActivityId = ee.getActivityId();//acitivtyId，即流程节点ID
        BpmnModel bpmnModel = repositoryService.getBpmnModel(ee.getProcessDefinitionId());
        Map<String, FlowElement> flowElementMap = bpmnModel.getMainProcess().getFlowElementMap();
        Map<String, List<String>> target2sourceMap = new HashMap<>();
        List<FlowElement> sequenceFlowList = flowElementMap.values().stream().filter(e -> e instanceof SequenceFlow).collect(Collectors.toList());
        for (FlowElement flowElement : sequenceFlowList) {
            String targetRef = ((SequenceFlow) flowElement).getTargetRef();
            String sourceRef = ((SequenceFlow) flowElement).getSourceRef();
            if (target2sourceMap.containsKey(targetRef)) {
                List<String> strings = target2sourceMap.get(targetRef);
                strings.add(sourceRef);
            } else {
                target2sourceMap.put(targetRef, CollectionUtil.newArrayList(sourceRef));
            }
        }
        List<HistoricActivityInstance> historyList = historyService.createHistoricActivityInstanceQuery().processInstanceId(processid).orderByHistoricActivityInstanceStartTime().desc().list();

        List<String> sourceElementList = getAllSourceList(currentActivityId, historyList, target2sourceMap, historyList.get(0).getStartTime());

        List<UserTask> list = flowElementMap.values().stream().filter(e -> e instanceof UserTask).map(e -> (UserTask) e).collect(Collectors.toList());
        Map<String, String> keyNameMap = list.stream().collect(Collectors.toMap(UserTask::getId, UserTask::getName));
        List<TaskDefinitionDto> res = new ArrayList<>();
        new HashSet<>(sourceElementList).forEach(e -> {
            if (keyNameMap.get(e) != null){
                TaskDefinitionDto taskDefinitionDto = new TaskDefinitionDto();
                taskDefinitionDto.setTaskDefinitionKey(e);
                taskDefinitionDto.setTaskName(keyNameMap.get(e));
                res.add(taskDefinitionDto);
            }
        });
        return FlowableResponse.success(res);
//        return FlowableResponse.success(new HashSet<>(sourceElement));
    }

    /**
     * 获取所有真实前置节点
     *  todo 暴力解法，待优化
     */

    private List<String> getAllSourceList(String currentActivityId, List<HistoricActivityInstance> historyList, Map<String, List<String>> target2sourceMap, Date opTime) {
        if (currentActivityId.equals("beforeRaiseDocAuditTask")) {
            System.out.println("**");
        }
        List<String> res = new ArrayList<>();
        List<String> strings = target2sourceMap.get(currentActivityId);
        if (CollectionUtils.isEmpty(strings)) {
            return res;
        }
        Set<String> set = new HashSet<>();
        if (strings.size() == 1) {
            HistoricActivityInstance historicActivityInstance = historyList.stream().filter(e -> ObjectUtil.isNotNull(e.getEndTime()) && StrUtil.equals(strings.get(0), e.getActivityId()) && DateUtil.compare(e.getStartTime(), opTime) <= 0).findFirst().get();
            if (historicActivityInstance.getDurationInMillis() > 50) {
                set.add(historicActivityInstance.getActivityId());
            }
            set.addAll(getAllSourceList(strings.get(0), historyList, target2sourceMap, historicActivityInstance.getStartTime()));
        } else {
            Date time = new Date();
            for (int i = 0; i < strings.size(); i++) {
                int finalI = i;
                Optional<HistoricActivityInstance> optional = historyList.stream().filter(e -> ObjectUtil.isNotNull(e.getEndTime()) && StrUtil.equals(strings.get(finalI), e.getActivityId()) && DateUtil.compare(e.getStartTime(), opTime) <= 0).findFirst();
                if (!optional.isEmpty()){
                    HistoricActivityInstance historicActivityInstance = optional.get();
                    time = DateUtil.compare(historicActivityInstance.getStartTime(), time) <= 0 ? time : historicActivityInstance.getStartTime();
                    if (historicActivityInstance.getDurationInMillis() < 50) {
                        set.addAll(getAllSourceList(strings.get(finalI), historyList, target2sourceMap, historicActivityInstance.getStartTime()));
                    } else {
                        set.add(historicActivityInstance.getActivityId());
                        set.addAll(getAllSourceList(strings.get(finalI), historyList, target2sourceMap, time));
                    }
                }
            }
        }
        res.addAll(set);
        return res;
    }


    @RequestMapping(method = RequestMethod.POST, value = "/return2SelectNode")
    @ApiOperation(value = "退回至指定节点", notes = "退回至指定节点")
    public FlowableResponse return2SelectNode(@RequestBody ParamRollbackDto params) {
        String processid = null;
        String taskId;
        String content;
        String sysid;
        String comment;
        String targetTask;
        Comment commentEntity = null;
        try {
            comment = params.getComment();
            if (StrUtil.isBlank(comment)) {
                comment = params.getCommentDto().getFullMessage();
            }
            taskId = params.getTaskId();
            if (StrUtil.isEmpty(taskId)) {
                return FlowableResponse.error("任务流程回退失败，taskId不能为空");
            }
            content = params.getContent();
//            if (StrUtil.isEmpty(content)) {
//                return FlowableResponse.error("任务流程回退失败，content不能为空");
//            }
            sysid = params.getSysid();
            if (StrUtil.isEmpty(sysid)) {
                return FlowableResponse.error("任务流程回退失败，sysid不能为空");
            }
            targetTask = params.getTargetTask();
            if (StrUtil.isEmpty(targetTask)) {
                return FlowableResponse.error("任务流程回退失败，targetTask不能为空");
            }
        } catch (Exception e) {
            return FlowableResponse.error("任务流程回退失败，参数获取异常！ message=" + e.getMessage());
        }
        try {
            Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
            processid = task.getProcessInstanceId();
            BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());
            Map<String, FlowElement> flowElementMap = bpmnModel.getMainProcess().getFlowElementMap();
            //预添加comment，有异常的话在catch中删除
            List<UserTask> list = flowElementMap.values().stream().filter(e -> e instanceof UserTask).map(e -> (UserTask) e).collect(Collectors.toList());
            Map<String, String> keyNameMap = list.stream().collect(Collectors.toMap(UserTask::getId, UserTask::getName));
            if (StrUtil.isBlank(params.getUserId())) {
                Authentication.setAuthenticatedUserId(task.getAssignee());
            } else {
                Authentication.setAuthenticatedUserId(params.getUserId());
            }
            if (StrUtil.isNotBlank(comment)) {
                commentEntity = taskService.addComment(taskId, processid, FlowableConstant.BACK_TAG + "退回至指定节点：" + keyNameMap.get(targetTask) +".意见:"+ comment);
                flowableCommentSupplementService.signTask(taskId);
            } else {
                commentEntity = taskService.addComment(taskId, processid, FlowableConstant.BACK_TAG + "退回至指定节点：" + keyNameMap.get(targetTask));
                flowableCommentSupplementService.signTask(taskId);
            }
            Map<String, List<String>> target2sourceMap = new HashMap<>();
            List<FlowElement> sequenceFlowList = flowElementMap.values().stream().filter(e -> e instanceof SequenceFlow).collect(Collectors.toList());
            for (FlowElement flowElement : sequenceFlowList) {
                String targetRef = ((SequenceFlow) flowElement).getTargetRef();
                String sourceRef = ((SequenceFlow) flowElement).getSourceRef();
                if (target2sourceMap.containsKey(targetRef)) {
                    List<String> strings = target2sourceMap.get(targetRef);
                    strings.add(sourceRef);
                } else {
                    target2sourceMap.put(targetRef, CollectionUtil.newArrayList(sourceRef));
                }
            }
            //获取所有当前active 且 属于回退到的节点的后置节点  的执行实例。
            List<String> currentExecutionIds = new ArrayList<>();
            List<Execution> executions = runtimeService.createExecutionQuery().parentId(processid).list();
            for (Execution execution : executions) {
                logger.info("执行实例节点：" + execution.getActivityId());
                FlowElement fe = bpmnModel.getFlowElement(execution.getActivityId());
                if (fe == null) {
                    continue;
                }
                if (fe instanceof Gateway) {
                    List<HistoricActivityInstance> sequenceFlow = historyService.createHistoricActivityInstanceQuery().processInstanceId(processid).executionId(execution.getId()).activityType("sequenceFlow").list();
                    SequenceFlow sqf = (SequenceFlow) bpmnModel.getFlowElement(sequenceFlow.get(0).getActivityId());
                    logger.info("网关exe{}所关联flow : {}", execution.getId(), sqf);
                    int count = 0;
                    if (isBelongtoSourceByFlowMap(target2sourceMap.get(sqf.getSourceRef()), targetTask, target2sourceMap, count)) {
                        currentExecutionIds.add(execution.getId());
                    }
                } else {
                    List<String> sourceList = target2sourceMap.get(execution.getActivityId());
                    int count = 0;
                    if (isBelongtoSourceByFlowMap(sourceList, targetTask, target2sourceMap, count)) {
                        currentExecutionIds.add(execution.getId());
                    }
                }
            }
            runtimeService.createChangeActivityStateBuilder().processInstanceId(processid)
                    .moveExecutionsToSingleActivityId(currentExecutionIds, targetTask).changeState();
            //入库
            ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processid).singleResult();
            //入库后更新变量
            //查看是否有新的变量传入
            Map<String, Object> existVar = runtimeService.getVariables(pi.getProcessInstanceId());
            //如果有，更新流程变量
            if (CollectionUtil.isNotEmpty(params.getTaskAssignee())) {
                Map<String, Object> existAssignee = CollectionUtil.isNotEmpty(existVar) ? (Map<String, Object>) existVar.getOrDefault("taskAssignee", new HashMap<>()) : new HashMap<>();
                existAssignee.putAll(params.getTaskAssignee());
                runtimeService.setVariable(pi.getProcessInstanceId(), "taskAssignee", existAssignee);
            }
            if (CollectionUtil.isNotEmpty(params.getConditionalVariable())) {
                Map<String, Object> existConditionalVariable = CollectionUtil.isNotEmpty(existVar) ? (Map<String, Object>) existVar.getOrDefault("conditionalVariable", new HashMap<>()) : new HashMap<>();
                existConditionalVariable.putAll(params.getConditionalVariable());
                runtimeService.setVariable(pi.getProcessInstanceId(), "conditionalVariable", existConditionalVariable);
            }
            //回退
            flowableDetailService.addProcessInstanceByTask(task, pi, sysid, content, pi.getName(), "return2SelectNode");
        } catch (Exception e) {
            logger.error("任务流程回退失败，请检查！taskid=" + taskId + ",taskKey=" + targetTask, e);
            if (ObjectUtil.isNotNull(commentEntity)) {
                taskService.deleteComment(commentEntity.getId());
            }
            return FlowableResponse.error("任务流程回退失败", "回退失败，请检查！taskid=" + taskId + ",targetTaskKey=" + targetTask + ",e.getMessage=" + e.getMessage());
        }
        return FlowableResponse.success(new ResponseMsgDto("任务流程回退成功"));
    }

    @RequestMapping(method = RequestMethod.GET, value = "getTaskBaseInfo")
    public List<Map<String, String>> getTaskBaseInfo(@RequestParam(value = "processKey") String processKey,
                                                          @RequestParam(value = "sysid") String sysid) {
        List<FlowableTenant> flowableTenants = flowableTenantService.queryAllTenant();
        FlowableTenant flowableTenant = flowableTenants.stream().filter(tenant -> (StrUtil.equals(processKey, tenant.getProcessDefinitionKey()) && StrUtil.equals(sysid, tenant.getSysid()))).findFirst().orElse(null);
        BpmnModel bpmnModel = repositoryService.getBpmnModel(flowableTenant.getLatestProcessDefinitionId());
        Collection<FlowElement> flowElements = bpmnModel.getMainProcess().getFlowElements();
        List<Map<String, String>> list = new ArrayList<>();
        flowElements.forEach(fe -> {
            if (fe instanceof UserTask) {
                Map<String, String> map = new HashMap<>();

                map.put("process_key", bpmnModel.getMainProcess().getId());
                map.put("task_key", ((UserTask) fe).getId());
                map.put("task_name", ((UserTask) fe).getName());

                if (((UserTask) fe).getLoopCharacteristics() != null && StrUtil.isNotBlank(((UserTask) fe).getLoopCharacteristics().getInputDataItem())) {
                    map.put("task_group", ((UserTask) fe).getLoopCharacteristics().getInputDataItem());

                } else {
                    String assignee = ((UserTask) fe).getAssignee();
                    String s1 = StrUtil.removeAll(assignee, "${");
                    String s2 = StrUtil.removeAll(s1, "}");
                    map.put("task_group", s2);

                }
                list.add(map);
            }
        });
        return list;
    }

    /**
     *  select a.*, c.NAME_, c.BYTES_ from t_flowable_tenant a left join ACT_RE_PROCDEF b on a.vc_latest_process_definition_id = b.ID_
     *  left join flowabledb.ACT_GE_BYTEARRAY c on b.DEPLOYMENT_ID_ = c.DEPLOYMENT_ID_
     *   where a.vc_process_definition_key = 'TestFlow' and vc_sysid = 'amprod'
     */
    @RequestMapping(method = RequestMethod.GET, value = "reBuildByName")
    public void reBuildByName(@RequestParam(value = "processKey") String processKey, @RequestParam(value = "sysid") String sysid) {
        FlowableTenant first = flowableTenantService.queryAllTenant().stream().filter(dto -> StrUtil.equals(dto.getProcessDefinitionKey(), processKey) && StrUtil.equals(dto.getSysid(), sysid)).findFirst().get();
        String md5 = SecureUtil.md5(ResourceUtil.getStream("processes/" + processKey + ".bpmn20.xml"));
        repositoryService.createDeployment().name(processKey).key(processKey).addClasspathResource("processes/" + processKey + ".bpmn20.xml").tenantId(first.getSysid()).deploy();
        ProcessDefinition ss = repositoryService.createProcessDefinitionQuery().processDefinitionKey(processKey).processDefinitionTenantId(first.getSysid()).orderByProcessDefinitionVersion().desc().list().get(0);
        first.setLatestProcessDefinitionId(ss.getId());
        first.setProcessDefinitionMd5(md5);
        flowableTenantService.updateVersion(first);
    }

    @RequestMapping(method = RequestMethod.POST, value = "reBuildByFile")
    public void reBuildByFile(@RequestParam(value = "processKey") String processKey, @RequestParam(value = "sysid") String sysid, @RequestPart(value = "file") MultipartFile file) throws IOException {
        repositoryService.createDeployment().name(processKey).key(processKey).addInputStream(file.getOriginalFilename(), file.getInputStream()).tenantId(sysid).deploy();
        FlowableTenant first = flowableTenantService.queryAllTenant().stream().filter(dto -> StrUtil.equals(dto.getProcessDefinitionKey(), processKey) && StrUtil.equals(dto.getSysid(), sysid)).findFirst().get();
        String md5 = SecureUtil.md5(file.getInputStream());
        ProcessDefinition ss = repositoryService.createProcessDefinitionQuery().processDefinitionKey(processKey).processDefinitionTenantId(sysid).orderByProcessDefinitionVersion().desc().list().get(0);
        first.setLatestProcessDefinitionId(ss.getId());
        first.setProcessDefinitionMd5(md5);
        flowableTenantService.updateVersion(first);
    }

}